1 /** @file
2   Thumb Dissassembler. Still a work in progress.
3 
4   Wrong output is a bug, so please fix it.
5   Hex output means there is not yet an entry or a decode bug.
6   gOpThumb[] are Thumb 16-bit, and gOpThumb2[] work on the 32-bit
7   16-bit stream of Thumb2 instruction. Then there are big case
8   statements to print everything out. If you are adding instructions
9   try to reuse existing case entries if possible.
10 
11   Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
12 
13   SPDX-License-Identifier: BSD-2-Clause-Patent
14 
15 **/
16 
17 #include <Base.h>
18 #include <Library/BaseLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/PrintLib.h>
21 
22 extern CHAR8 *gCondition[];
23 
24 extern CHAR8 *gReg[];
25 
26 // Thumb address modes
27 #define LOAD_STORE_FORMAT1            1
28 #define LOAD_STORE_FORMAT1_H        101
29 #define LOAD_STORE_FORMAT1_B        111
30 #define LOAD_STORE_FORMAT2            2
31 #define LOAD_STORE_FORMAT3            3
32 #define LOAD_STORE_FORMAT4            4
33 #define LOAD_STORE_MULTIPLE_FORMAT1   5
34 #define PUSH_FORMAT                   6
35 #define POP_FORMAT                  106
36 #define IMMED_8                       7
37 #define CONDITIONAL_BRANCH            8
38 #define UNCONDITIONAL_BRANCH          9
39 #define UNCONDITIONAL_BRANCH_SHORT  109
40 #define BRANCH_EXCHANGE              10
41 #define DATA_FORMAT1                 11
42 #define DATA_FORMAT2                 12
43 #define DATA_FORMAT3                 13
44 #define DATA_FORMAT4                 14
45 #define DATA_FORMAT5                 15
46 #define DATA_FORMAT6_SP              16
47 #define DATA_FORMAT6_PC             116
48 #define DATA_FORMAT7                 17
49 #define DATA_FORMAT8                 19
50 #define CPS_FORMAT                   20
51 #define ENDIAN_FORMAT                21
52 #define DATA_CBZ                     22
53 #define ADR_FORMAT                   23
54 #define IT_BLOCK                     24
55 
56 // Thumb2 address modes
57 #define B_T3                        200
58 #define B_T4                        201
59 #define BL_T2                       202
60 #define POP_T2                      203
61 #define POP_T3                      204
62 #define STM_FORMAT                  205
63 #define LDM_REG_IMM12_SIGNED        206
64 #define LDM_REG_IMM12_LSL           207
65 #define LDM_REG_IMM8                208
66 #define LDM_REG_IMM12               209
67 #define LDM_REG_INDIRECT_LSL        210
68 #define LDM_REG_IMM8_SIGNED         211
69 #define LDRD_REG_IMM8               212
70 #define LDREXB                      213
71 #define LDREXD                      214
72 #define SRS_FORMAT                  215
73 #define RFE_FORMAT                  216
74 #define LDRD_REG_IMM8_SIGNED        217
75 #define ADD_IMM12                   218
76 #define ADD_IMM5                    219
77 #define ADR_THUMB2                  220
78 #define CMN_THUMB2                  221
79 #define ASR_IMM5                    222
80 #define ASR_3REG                    223
81 #define BFC_THUMB2                  224
82 #define CDP_THUMB2                  225
83 #define THUMB2_NO_ARGS              226
84 #define THUMB2_2REGS                227
85 #define ADD_IMM5_2REG               228
86 #define CPD_THUMB2                  229
87 #define THUMB2_4REGS                230
88 #define ADD_IMM12_1REG              231
89 #define THUMB2_IMM16                232
90 #define MRC_THUMB2                  233
91 #define MRRC_THUMB2                 234
92 #define THUMB2_MRS                  235
93 #define THUMB2_MSR                  236
94 
95 
96 
97 
98 typedef struct {
99   CHAR8   *Start;
100   UINT32  OpCode;
101   UINT32  Mask;
102   UINT32  AddressMode;
103 } THUMB_INSTRUCTIONS;
104 
105 THUMB_INSTRUCTIONS gOpThumb[] = {
106 // Thumb 16-bit instrucitons
107 //          Op       Mask   Format
108   { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5 },  // ADC <Rndn>, <Rm>
109   { "ADR",  0xa000, 0xf800, ADR_FORMAT   },  // ADR <Rd>, <label>
110   { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2 },
111   { "ADD" , 0x3000, 0xf800, DATA_FORMAT3 },
112   { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1 },
113   { "ADD" , 0x4400, 0xff00, DATA_FORMAT8 },   // A8.6.9
114   { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC },
115   { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP },
116   { "ADD" , 0xb000, 0xff80, DATA_FORMAT7 },
117 
118   { "AND" , 0x4000, 0xffc0, DATA_FORMAT5 },
119 
120   { "ASR" , 0x1000, 0xf800, DATA_FORMAT4 },
121   { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5 },
122 
123   { "B"   , 0xd000, 0xf000, CONDITIONAL_BRANCH },
124   { "B"   , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT },
125   { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE },
126   { "BX"  , 0x4700, 0xff87, BRANCH_EXCHANGE },
127 
128   { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5 },
129   { "BKPT", 0xdf00, 0xff00, IMMED_8 },
130   { "CBZ",  0xb100, 0xfd00, DATA_CBZ },
131   { "CBNZ", 0xb900, 0xfd00, DATA_CBZ },
132   { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5 },
133 
134   { "CMP" , 0x2800, 0xf800, DATA_FORMAT3 },
135   { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5 },
136   { "CMP" , 0x4500, 0xff00, DATA_FORMAT8 },
137 
138   { "CPS" , 0xb660, 0xffe8, CPS_FORMAT },
139   { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
140   { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5 },
141 
142   { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
143   { "LDR"   , 0x6800, 0xf800, LOAD_STORE_FORMAT1 },  // LDR <Rt>, [<Rn> {,#<imm>}]
144   { "LDR"   , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },  // STR <Rt>, [<Rn>, <Rm>]
145   { "LDR"   , 0x4800, 0xf800, LOAD_STORE_FORMAT3 },
146   { "LDR"   , 0x9800, 0xf800, LOAD_STORE_FORMAT4 },  // LDR <Rt>, [SP, #<imm>]
147   { "LDRB"  , 0x7800, 0xf800, LOAD_STORE_FORMAT1_B },
148   { "LDRB"  , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2 },  // STR <Rt>, [<Rn>, <Rm>]
149   { "LDRH"  , 0x8800, 0xf800, LOAD_STORE_FORMAT1_H },
150   { "LDRH"  , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2 },
151   { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2 },  // STR <Rt>, [<Rn>, <Rm>]
152   { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2 },
153 
154   { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5 },   // LSL with imm5 == 0 is a MOVS, so this must go before LSL
155   { "LSL" , 0x0000, 0xf800, DATA_FORMAT4 },
156   { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5 },
157   { "LSR" , 0x0001, 0xf800, DATA_FORMAT4 },
158   { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5 },
159   { "LSRS", 0x0800, 0xf800, DATA_FORMAT4 },  // LSRS <Rd>, <Rm>, #<imm5>
160 
161   { "MOVS", 0x2000, 0xf800, DATA_FORMAT3 },
162   { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3 },
163   { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
164 
165   { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5 },
166   { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5 },
167   { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5 },
168   { "ORR" , 0x4300, 0xffc0, DATA_FORMAT5 },
169   { "POP" , 0xbc00, 0xfe00, POP_FORMAT },
170   { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT },
171 
172   { "REV"   , 0xba00, 0xffc0, DATA_FORMAT5 },
173   { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5 },
174   { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5 },
175 
176   { "ROR"    , 0x41c0, 0xffc0, DATA_FORMAT5 },
177   { "SBC"    , 0x4180, 0xffc0, DATA_FORMAT5 },
178   { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT },
179 
180   { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
181   { "STR"   , 0x6000, 0xf800, LOAD_STORE_FORMAT1 },   // STR  <Rt>, [<Rn> {,#<imm>}]
182   { "STR"   , 0x5000, 0xfe00, LOAD_STORE_FORMAT2 },   // STR  <Rt>, [<Rn>, <Rm>]
183   { "STR"   , 0x9000, 0xf800, LOAD_STORE_FORMAT4 },   // STR  <Rt>, [SP, #<imm>]
184   { "STRB"  , 0x7000, 0xf800, LOAD_STORE_FORMAT1_B }, // STRB <Rt>, [<Rn>, #<imm5>]
185   { "STRB"  , 0x5400, 0xfe00, LOAD_STORE_FORMAT2 },   // STRB <Rt>, [<Rn>, <Rm>]
186   { "STRH"  , 0x8000, 0xf800, LOAD_STORE_FORMAT1_H }, // STRH <Rt>, [<Rn>{,#<imm>}]
187   { "STRH"  , 0x5200, 0xfe00, LOAD_STORE_FORMAT2 },   // STRH <Rt>, [<Rn>, <Rm>]
188 
189   { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2 },
190   { "SUB" , 0x3800, 0xf800, DATA_FORMAT3 },
191   { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1 },
192   { "SUB" , 0xb080, 0xff80, DATA_FORMAT7 },
193 
194   { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5 },
195 
196   { "SWI" , 0xdf00, 0xff00, IMMED_8 },
197   { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5 },
198   { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5 },
199   { "TST" , 0x4200, 0xffc0, DATA_FORMAT5 },
200   { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5 },
201   { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5 },
202 
203   { "IT",   0xbf00, 0xff00, IT_BLOCK }
204 
205 };
206 
207 THUMB_INSTRUCTIONS gOpThumb2[] = {
208 //Instruct  OpCode      OpCode Mask  Addressig Mode
209 
210   { "ADR", 0xf2af0000, 0xfbff8000, ADR_THUMB2    },  // ADDR <Rd>, <label> ;Needs to go before ADDW
211   { "CMN", 0xf1100f00, 0xfff08f00, CMN_THUMB2    },  // CMN <Rn>, #<const> ;Needs to go before ADD
212   { "CMN", 0xeb100f00, 0xfff08f00, ADD_IMM5_2REG },  // CMN <Rn>, <Rm> {,<shift> #<const>}
213   { "CMP", 0xf1a00f00, 0xfff08f00, CMN_THUMB2    },  // CMP <Rn>, #<const>
214   { "TEQ", 0xf0900f00, 0xfff08f00, CMN_THUMB2    },  // CMP <Rn>, #<const>
215   { "TEQ", 0xea900f00, 0xfff08f00, ADD_IMM5_2REG },  // CMN <Rn>, <Rm> {,<shift> #<const>}
216   { "TST", 0xf0100f00, 0xfff08f00, CMN_THUMB2    },  // CMP <Rn>, #<const>
217   { "TST", 0xea100f00, 0xfff08f00, ADD_IMM5_2REG },  // TST <Rn>, <Rm> {,<shift> #<const>}
218 
219   { "MOV",  0xf04f0000, 0xfbef8000, ADD_IMM12_1REG }, // MOV  <Rd>, #<const>
220   { "MOVW", 0xf2400000, 0xfbe08000, THUMB2_IMM16 },   // MOVW <Rd>, #<const>
221   { "MOVT", 0xf2c00000, 0xfbe08000, THUMB2_IMM16 },   // MOVT <Rd>, #<const>
222 
223   { "ADC",  0xf1400000, 0xfbe08000, ADD_IMM12 }, // ADC{S}  <Rd>, <Rn>, #<const>
224   { "ADC",  0xeb400000, 0xffe08000, ADD_IMM5  }, // ADC{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
225   { "ADD",  0xf1000000, 0xfbe08000, ADD_IMM12 }, // ADD{S}  <Rd>, <Rn>, #<const>
226   { "ADD",  0xeb000000, 0xffe08000, ADD_IMM5  }, // ADD{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
227   { "ADDW", 0xf2000000, 0xfbe08000, ADD_IMM12 }, // ADDW{S} <Rd>, <Rn>, #<const>
228   { "AND",  0xf0000000, 0xfbe08000, ADD_IMM12 }, // AND{S}  <Rd>, <Rn>, #<const>
229   { "AND",  0xea000000, 0xffe08000, ADD_IMM5  }, // AND{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
230   { "BIC",  0xf0200000, 0xfbe08000, ADD_IMM12 }, // BIC{S}  <Rd>, <Rn>, #<const>
231   { "BIC",  0xea200000, 0xffe08000, ADD_IMM5  }, // BIC{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
232   { "EOR",  0xf0800000, 0xfbe08000, ADD_IMM12 }, // EOR{S}  <Rd>, <Rn>, #<const>
233   { "EOR",  0xea800000, 0xffe08000, ADD_IMM5  }, // EOR{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
234   { "ORN",  0xf0600000, 0xfbe08000, ADD_IMM12 }, // ORN{S}  <Rd>, <Rn>, #<const>
235   { "ORN",  0xea600000, 0xffe08000, ADD_IMM5  }, // ORN{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
236   { "ORR",  0xf0400000, 0xfbe08000, ADD_IMM12 }, // ORR{S}  <Rd>, <Rn>, #<const>
237   { "ORR",  0xea400000, 0xffe08000, ADD_IMM5  }, // ORR{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
238   { "RSB",  0xf1c00000, 0xfbe08000, ADD_IMM12 }, // RSB{S}  <Rd>, <Rn>, #<const>
239   { "RSB",  0xebc00000, 0xffe08000, ADD_IMM5  }, // RSB{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
240   { "SBC",  0xf1600000, 0xfbe08000, ADD_IMM12 }, // SBC{S}  <Rd>, <Rn>, #<const>
241   { "SBC",  0xeb600000, 0xffe08000, ADD_IMM5  }, // SBC{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
242   { "SUB",  0xf1a00000, 0xfbe08000, ADD_IMM12 }, // SUB{S}  <Rd>, <Rn>, #<const>
243   { "SUB",  0xeba00000, 0xffe08000, ADD_IMM5  }, // SUB{S}  <Rd>, <Rn>, <Rm> {,<shift> #<const>}
244 
245   { "ASR",  0xea4f0020, 0xffef8030, ASR_IMM5 },  // ARS  <Rd>, <Rm> #<const>} imm3:imm2
246   { "ASR",  0xfa40f000, 0xffe0f0f0, ASR_3REG },  // ARS  <Rd>, <Rn>, <Rm>
247   { "LSR",  0xea4f0010, 0xffef8030, ASR_IMM5 },  // LSR  <Rd>, <Rm> #<const>} imm3:imm2
248   { "LSR",  0xfa20f000, 0xffe0f0f0, ASR_3REG },  // LSR  <Rd>, <Rn>, <Rm>
249   { "ROR",  0xea4f0030, 0xffef8030, ASR_IMM5 },  // ROR  <Rd>, <Rm> #<const>} imm3:imm2
250   { "ROR",  0xfa60f000, 0xffe0f0f0, ASR_3REG },  // ROR  <Rd>, <Rn>, <Rm>
251 
252   { "BFC",  0xf36f0000, 0xffff8010, BFC_THUMB2 },   // BFC  <Rd>, #<lsb>, #<width>
253   { "BIC",  0xf3600000, 0xfff08010, BFC_THUMB2 },   // BIC  <Rn>, <Rd>, #<lsb>, #<width>
254   { "SBFX", 0xf3400000, 0xfff08010, BFC_THUMB2 },   // SBFX <Rn>, <Rd>, #<lsb>, #<width>
255   { "UBFX", 0xf3c00000, 0xfff08010, BFC_THUMB2 },   // UBFX <Rn>, <Rd>, #<lsb>, #<width>
256 
257   { "CPD",  0xee000000, 0xff000010, CPD_THUMB2 },  // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
258   { "CPD2", 0xfe000000, 0xff000010, CPD_THUMB2 },  // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
259 
260   { "MRC",   0xee100000, 0xff100000, MRC_THUMB2 },  // MRC  <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
261   { "MRC2",  0xfe100000, 0xff100000, MRC_THUMB2 },  // MRC2 <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
262   { "MRRC",  0xec500000, 0xfff00000, MRRC_THUMB2 },  // MRRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
263   { "MRRC2", 0xfc500000, 0xfff00000, MRRC_THUMB2 },  // MRR2 <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
264 
265   { "MRS",   0xf3ef8000, 0xfffff0ff, THUMB2_MRS  }, // MRS  <Rd>, CPSR
266   { "MSR",   0xf3808000, 0xfff0fcff, THUMB2_MSR  }, // MSR  CPSR_fs, <Rn>
267 
268   { "CLREX", 0xf3bf8f2f, 0xfffffff, THUMB2_NO_ARGS }, // CLREX
269 
270   { "CLZ",   0xfab0f080, 0xfff0f0f0, THUMB2_2REGS },  // CLZ    <Rd>,<Rm>
271   { "MOV",   0xec4f0000, 0xfff0f0f0, THUMB2_2REGS },  // MOV    <Rd>,<Rm>
272   { "MOVS",  0xec5f0000, 0xfff0f0f0, THUMB2_2REGS },  // MOVS   <Rd>,<Rm>
273   { "RBIT",  0xfb90f0a0, 0xfff0f0f0, THUMB2_2REGS },  // RBIT   <Rd>,<Rm>
274   { "REV",   0xfb90f080, 0xfff0f0f0, THUMB2_2REGS },  // REV    <Rd>,<Rm>
275   { "REV16", 0xfa90f090, 0xfff0f0f0, THUMB2_2REGS },  // REV16  <Rd>,<Rm>
276   { "REVSH", 0xfa90f0b0, 0xfff0f0f0, THUMB2_2REGS },  // REVSH  <Rd>,<Rm>
277   { "RRX",   0xea4f0030, 0xfffff0f0, THUMB2_2REGS },  // RRX    <Rd>,<Rm>
278   { "RRXS",  0xea5f0030, 0xfffff0f0, THUMB2_2REGS },  // RRXS   <Rd>,<Rm>
279 
280   { "MLA",   0xfb000000, 0xfff000f0, THUMB2_4REGS }, // MLA <Rd>, <Rn>, <Rm>, <Ra>
281   { "MLS",   0xfb000010, 0xfff000f0, THUMB2_4REGS }, // MLA <Rd>, <Rn>, <Rm>, <Ra>
282 
283 
284   { "SMLABB",  0xfb100000, 0xfff000f0, THUMB2_4REGS }, // SMLABB   <Rd>, <Rn>, <Rm>, <Ra>
285   { "SMLABT",  0xfb100010, 0xfff000f0, THUMB2_4REGS }, // SMLABT   <Rd>, <Rn>, <Rm>, <Ra>
286   { "SMLABB",  0xfb100020, 0xfff000f0, THUMB2_4REGS }, // SMLATB   <Rd>, <Rn>, <Rm>, <Ra>
287   { "SMLATT",  0xfb100030, 0xfff000f0, THUMB2_4REGS }, // SMLATT   <Rd>, <Rn>, <Rm>, <Ra>
288   { "SMLAWB",  0xfb300000, 0xfff000f0, THUMB2_4REGS }, // SMLAWB   <Rd>, <Rn>, <Rm>, <Ra>
289   { "SMLAWT",  0xfb300010, 0xfff000f0, THUMB2_4REGS }, // SMLAWT   <Rd>, <Rn>, <Rm>, <Ra>
290   { "SMLSD",   0xfb400000, 0xfff000f0, THUMB2_4REGS }, // SMLSD    <Rd>, <Rn>, <Rm>, <Ra>
291   { "SMLSDX",  0xfb400010, 0xfff000f0, THUMB2_4REGS }, // SMLSDX   <Rd>, <Rn>, <Rm>, <Ra>
292   { "SMMLA",   0xfb500000, 0xfff000f0, THUMB2_4REGS }, // SMMLA    <Rd>, <Rn>, <Rm>, <Ra>
293   { "SMMLAR",  0xfb500010, 0xfff000f0, THUMB2_4REGS }, // SMMLAR   <Rd>, <Rn>, <Rm>, <Ra>
294   { "SMMLS",   0xfb600000, 0xfff000f0, THUMB2_4REGS }, // SMMLS    <Rd>, <Rn>, <Rm>, <Ra>
295   { "SMMLSR",  0xfb600010, 0xfff000f0, THUMB2_4REGS }, // SMMLSR   <Rd>, <Rn>, <Rm>, <Ra>
296   { "USADA8",  0xfb700000, 0xfff000f0, THUMB2_4REGS }, // USADA8   <Rd>, <Rn>, <Rm>, <Ra>
297   { "SMLAD",   0xfb200000, 0xfff000f0, THUMB2_4REGS }, // SMLAD    <Rd>, <Rn>, <Rm>, <Ra>
298   { "SMLADX",  0xfb200010, 0xfff000f0, THUMB2_4REGS }, // SMLADX   <Rd>, <Rn>, <Rm>, <Ra>
299 
300 
301   { "B",    0xf0008000, 0xf800d000, B_T3  },             // B<c> <label>
302   { "B",    0xf0009000, 0xf800d000, B_T4  },             // B<c> <label>
303   { "BL",   0xf000d000, 0xf800d000, B_T4  },             // BL<c> <label>
304   { "BLX",  0xf000c000, 0xf800d000, BL_T2 },             // BLX<c> <label>
305 
306   { "POP",   0xe8bd0000, 0xffff2000, POP_T2 },           // POP <registers>
307   { "POP",   0xf85d0b04, 0xffff0fff, POP_T3 },           // POP <register>
308   { "PUSH",  0xe8ad0000, 0xffffa000, POP_T2 },           // PUSH <registers>
309   { "PUSH",  0xf84d0d04, 0xffff0fff, POP_T3 },           // PUSH <register>
310   { "STM"  , 0xe8800000, 0xffd0a000,  STM_FORMAT },      // STM <Rn>{!},<registers>
311   { "STMDB", 0xe9800000, 0xffd0a000,  STM_FORMAT },      // STMDB <Rn>{!},<registers>
312   { "LDM"  , 0xe8900000, 0xffd02000,  STM_FORMAT },      // LDM <Rn>{!},<registers>
313   { "LDMDB", 0xe9100000, 0xffd02000,  STM_FORMAT },      // LDMDB <Rn>{!},<registers>
314 
315   { "LDR",   0xf8d00000, 0xfff00000,  LDM_REG_IMM12 },          // LDR   <rt>, [<rn>, {, #<imm12>]}
316   { "LDRB",  0xf8900000, 0xfff00000,  LDM_REG_IMM12 },          // LDRB  <rt>, [<rn>, {, #<imm12>]}
317   { "LDRH",  0xf8b00000, 0xfff00000,  LDM_REG_IMM12 },          // LDRH  <rt>, [<rn>, {, #<imm12>]}
318   { "LDRSB", 0xf9900000, 0xfff00000,  LDM_REG_IMM12 },          // LDRSB <rt>, [<rn>, {, #<imm12>]}
319   { "LDRSH", 0xf9b00000, 0xfff00000,  LDM_REG_IMM12 },          // LDRSH <rt>, [<rn>, {, #<imm12>]}
320 
321   { "LDR",   0xf85f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDR   <Rt>, <label>
322   { "LDRB",  0xf81f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDRB  <Rt>, <label>
323   { "LDRH",  0xf83f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDRH  <Rt>, <label>
324   { "LDRSB", 0xf91f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDRSB <Rt>, <label>
325   { "LDRSH", 0xf93f0000, 0xff7f0000,  LDM_REG_IMM12_SIGNED },   // LDRSB <Rt>, <label>
326 
327   { "LDR",   0xf8500000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDR   <rt>, [<rn>, <rm> {, LSL #<imm2>]}
328   { "LDRB",  0xf8100000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDRB  <rt>, [<rn>, <rm> {, LSL #<imm2>]}
329   { "LDRH",  0xf8300000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDRH  <rt>, [<rn>, <rm> {, LSL #<imm2>]}
330   { "LDRSB", 0xf9100000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
331   { "LDRSH", 0xf9300000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
332 
333   { "LDR",   0xf8500800, 0xfff00800,  LDM_REG_IMM8 },           // LDR    <rt>, [<rn>, {, #<imm8>]}
334   { "LDRBT", 0xf8100e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRBT  <rt>, [<rn>, {, #<imm8>]}
335   { "LDRHT", 0xf8300e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRHT  <rt>, [<rn>, {, #<imm8>]}
336   { "LDRSB", 0xf9100800, 0xfff00800,  LDM_REG_IMM8 },           // LDRHT  <rt>, [<rn>, {, #<imm8>]}  {!} form?
337   { "LDRSBT",0xf9100e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRHBT <rt>, [<rn>, {, #<imm8>]}  {!} form?
338   { "LDRSH" ,0xf9300800, 0xfff00800,  LDM_REG_IMM8 },           // LDRSH  <rt>, [<rn>, {, #<imm8>]}
339   { "LDRSHT",0xf9300e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRSHT <rt>, [<rn>, {, #<imm8>]}
340   { "LDRT",  0xf8500e00, 0xfff00f00,  LDM_REG_IMM8 },           // LDRT   <rt>, [<rn>, {, #<imm8>]}
341 
342   { "LDRD",  0xe8500000, 0xfe500000,  LDRD_REG_IMM8_SIGNED },   // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
343   { "LDRD",  0xe8500000, 0xfe500000,  LDRD_REG_IMM8       },    // LDRD <rt>, <rt2>, <label>
344 
345   { "LDREX",  0xe8500f00, 0xfff00f00,  LDM_REG_IMM8 },           // LDREX <Rt>, [Rn, {#imm8}]]
346   { "LDREXB", 0xe8d00f4f, 0xfff00fff,  LDREXB  },                // LDREXB <Rt>, [<Rn>]
347   { "LDREXH", 0xe8d00f5f, 0xfff00fff,  LDREXB  },                // LDREXH <Rt>, [<Rn>]
348 
349   { "LDREXD", 0xe8d00f4f, 0xfff00fff,  LDREXD  },                // LDREXD <Rt>, <Rt2>, [<Rn>]
350 
351   { "STR",   0xf8c00000, 0xfff00000,  LDM_REG_IMM12 },          // STR   <rt>, [<rn>, {, #<imm12>]}
352   { "STRB",  0xf8800000, 0xfff00000,  LDM_REG_IMM12 },          // STRB  <rt>, [<rn>, {, #<imm12>]}
353   { "STRH",  0xf8a00000, 0xfff00000,  LDM_REG_IMM12 },          // STRH  <rt>, [<rn>, {, #<imm12>]}
354 
355   { "STR",   0xf8400000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // STR   <rt>, [<rn>, <rm> {, LSL #<imm2>]}
356   { "STRB",  0xf8000000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // STRB  <rt>, [<rn>, <rm> {, LSL #<imm2>]}
357   { "STRH",  0xf8200000, 0xfff00fc0,  LDM_REG_INDIRECT_LSL },   // STRH  <rt>, [<rn>, <rm> {, LSL #<imm2>]}
358 
359   { "STR",   0xf8400800, 0xfff00800,  LDM_REG_IMM8 },           // STR    <rt>, [<rn>, {, #<imm8>]}
360   { "STRH",  0xf8200800, 0xfff00800,  LDM_REG_IMM8 },           // STRH   <rt>, [<rn>, {, #<imm8>]}
361   { "STRBT", 0xf8000e00, 0xfff00f00,  LDM_REG_IMM8 },           // STRBT  <rt>, [<rn>, {, #<imm8>]}
362   { "STRHT", 0xf8200e00, 0xfff00f00,  LDM_REG_IMM8 },           // STRHT  <rt>, [<rn>, {, #<imm8>]}
363   { "STRT",  0xf8400e00, 0xfff00f00,  LDM_REG_IMM8 },           // STRT   <rt>, [<rn>, {, #<imm8>]}
364 
365   { "STRD",  0xe8400000, 0xfe500000,  LDRD_REG_IMM8_SIGNED },    // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
366 
367   { "STREX",  0xe8400f00, 0xfff00f00,  LDM_REG_IMM8 },           // STREX <Rt>, [Rn, {#imm8}]]
368   { "STREXB", 0xe8c00f4f, 0xfff00fff,  LDREXB  },                // STREXB <Rd>, <Rt>, [<Rn>]
369   { "STREXH", 0xe8c00f5f, 0xfff00fff,  LDREXB  },                // STREXH <Rd>, <Rt>, [<Rn>]
370 
371   { "STREXD", 0xe8d00f4f, 0xfff00fff,  LDREXD  },                // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
372 
373   { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT },       // SRSDB<c> SP{!},#<mode>
374   { "SRS"  , 0xe98dc000, 0xffdffff0, SRS_FORMAT },       // SRS{IA}<c> SP{!},#<mode>
375   { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT },       // RFEDB<c> <Rn>{!}
376   { "RFE"  , 0xe990c000, 0xffd0ffff, RFE_FORMAT }        // RFE{IA}<c> <Rn>{!}
377 };
378 
379 CHAR8 *gShiftType[] = {
380   "LSL",
381   "LSR",
382   "ASR",
383   "ROR"
384 };
385 
386 CHAR8 mThumbMregListStr[4*15 + 1];
387 
388 CHAR8 *
ThumbMRegList(UINT32 RegBitMask)389 ThumbMRegList (
390   UINT32  RegBitMask
391   )
392 {
393   UINTN     Index, Start, End;
394   BOOLEAN   First;
395 
396   mThumbMregListStr[0] = '\0';
397   AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "{");
398 
399   for (Index = 0, First = TRUE; Index <= 15; Index++) {
400     if ((RegBitMask & (1 << Index)) != 0) {
401       Start = End = Index;
402       for (Index++; ((RegBitMask & (1 << Index)) != 0) && (Index <= 9); Index++) {
403         End = Index;
404       }
405 
406       if (!First) {
407         AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, ",");
408       } else {
409         First = FALSE;
410       }
411 
412       if (Start == End) {
413         AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, gReg[Start]);
414       } else {
415         AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, gReg[Start]);
416         AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "-");
417         AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, gReg[End]);
418       }
419     }
420   }
421   if (First) {
422     AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "ERROR");
423   }
424   AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "}");
425 
426   // BugBug: Make caller pass in buffer it is cleaner
427   return mThumbMregListStr;
428 }
429 
430 UINT32
SignExtend32(IN UINT32 Data,IN UINT32 TopBit)431 SignExtend32 (
432   IN  UINT32  Data,
433   IN  UINT32  TopBit
434   )
435 {
436   if (((Data & TopBit) == 0) || (TopBit == BIT31)) {
437     return Data;
438   }
439 
440   do {
441     TopBit <<= 1;
442     Data |= TopBit;
443   } while ((TopBit & BIT31) != BIT31);
444 
445   return Data;
446 }
447 
448 //
449 // Some instructions specify the PC is always considered aligned
450 // The PC is after the instruction that is excuting. So you pass
451 // in the instruction address and you get back the aligned answer
452 //
453 UINT32
PCAlign4(IN UINT32 Data)454 PCAlign4 (
455   IN  UINT32  Data
456   )
457 {
458   return (Data + 4) & 0xfffffffc;
459 }
460 
461 /**
462   Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
463   point to next instructin.
464 
465   We cheat and only decode instructions that access
466   memory. If the instruction is not found we dump the instruction in hex.
467 
468   @param  OpCodePtrPtr  Pointer to pointer of ARM Thumb instruction to disassemble.
469   @param  Buf           Buffer to sprintf disassembly into.
470   @param  Size          Size of Buf in bytes.
471   @param  Extended    TRUE dump hex for instruction too.
472 
473 **/
474 VOID
DisassembleThumbInstruction(IN UINT16 ** OpCodePtrPtr,OUT CHAR8 * Buf,OUT UINTN Size,OUT UINT32 * ItBlock,IN BOOLEAN Extended)475 DisassembleThumbInstruction (
476   IN  UINT16    **OpCodePtrPtr,
477   OUT CHAR8     *Buf,
478   OUT UINTN     Size,
479   OUT UINT32    *ItBlock,
480   IN  BOOLEAN   Extended
481   )
482 {
483   UINT16  *OpCodePtr;
484   UINT16  OpCode;
485   UINT32  OpCode32;
486   UINT32  Index;
487   UINT32  Offset;
488   UINT16  Rd, Rn, Rm, Rt, Rt2;
489   BOOLEAN H1, H2, imod;
490   //BOOLEAN ItFlag;
491   UINT32  PC, Target, msbit, lsbit;
492   CHAR8   *Cond;
493   BOOLEAN S, J1, J2, P, U, W;
494   UINT32  coproc, opc1, opc2, CRd, CRn, CRm;
495   UINT32  Mask;
496 
497   OpCodePtr = *OpCodePtrPtr;
498   OpCode = **OpCodePtrPtr;
499 
500   // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
501   OpCode32 = (((UINT32)OpCode) << 16) | *(OpCodePtr + 1);
502 
503   // These register names match branch form, but not others
504   Rd = OpCode & 0x7;
505   Rn = (OpCode >> 3) & 0x7;
506   Rm = (OpCode >> 6) & 0x7;
507   H1 = (OpCode & BIT7) != 0;
508   H2 = (OpCode & BIT6) != 0;
509   imod = (OpCode & BIT4) != 0;
510   PC = (UINT32)(UINTN)OpCodePtr;
511 
512   // Increment by the minimum instruction size, Thumb2 could be bigger
513   *OpCodePtrPtr += 1;
514 
515   // Manage IT Block ItFlag TRUE means we are in an IT block
516   /*if (*ItBlock != 0) {
517     ItFlag = TRUE;
518     *ItBlock -= 1;
519   } else {
520     ItFlag = FALSE;
521   }*/
522 
523   for (Index = 0; Index < sizeof (gOpThumb)/sizeof (THUMB_INSTRUCTIONS); Index++) {
524     if ((OpCode & gOpThumb[Index].Mask) == gOpThumb[Index].OpCode) {
525       if (Extended) {
526         Offset = AsciiSPrint (Buf, Size, "0x%04x       %-6a", OpCode, gOpThumb[Index].Start);
527       } else {
528         Offset = AsciiSPrint (Buf, Size, "%-6a", gOpThumb[Index].Start);
529       }
530       switch (gOpThumb[Index].AddressMode) {
531       case LOAD_STORE_FORMAT1:
532         // A6.5.1  <Rd>, [<Rn>, #<5_bit_offset>]
533         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 4) & 0x7c);
534         return;
535       case LOAD_STORE_FORMAT1_H:
536         // A6.5.1  <Rd>, [<Rn>, #<5_bit_offset>]
537         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 5) & 0x3e);
538         return;
539       case LOAD_STORE_FORMAT1_B:
540         // A6.5.1  <Rd>, [<Rn>, #<5_bit_offset>]
541         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 6) & 0x1f);
542         return;
543 
544       case LOAD_STORE_FORMAT2:
545         // A6.5.1  <Rd>, [<Rn>, <Rm>]
546         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d, r%d]", Rd, Rn, Rm);
547         return;
548       case LOAD_STORE_FORMAT3:
549         // A6.5.1 <Rd>, [PC, #<8_bit_offset>]
550         Target = (OpCode & 0xff) << 2;
551         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [pc, #0x%x] ;0x%08x", (OpCode >> 8) & 7, Target, PCAlign4 (PC) + Target);
552         return;
553       case LOAD_STORE_FORMAT4:
554         // Rt, [SP, #imm8]
555         Target = (OpCode & 0xff) << 2;
556         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [sp, #0x%x]", (OpCode >> 8) & 7, Target);
557         return;
558 
559       case LOAD_STORE_MULTIPLE_FORMAT1:
560         // <Rn>!, {r0-r7}
561         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (OpCode & 0xff));
562         return;
563 
564       case POP_FORMAT:
565         // POP {r0-r7,pc}
566         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT15 : 0)));
567         return;
568 
569       case PUSH_FORMAT:
570         // PUSH {r0-r7,lr}
571         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT14 : 0)));
572         return;
573 
574 
575       case IMMED_8:
576         // A6.7 <immed_8>
577         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%x", OpCode & 0xff);
578         return;
579 
580       case CONDITIONAL_BRANCH:
581         // A6.3.1 B<cond> <target_address>
582         // Patch in the condition code. A little hack but based on "%-6a"
583         Cond = gCondition[(OpCode >> 8) & 0xf];
584         Buf[Offset-5] = *Cond++;
585         Buf[Offset-4] = *Cond;
586         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x",  PC + 4 + SignExtend32 ((OpCode & 0xff) << 1, BIT8));
587         return;
588       case UNCONDITIONAL_BRANCH_SHORT:
589         // A6.3.2 B  <target_address>
590         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0x3ff) << 1, BIT11));
591         return;
592 
593       case BRANCH_EXCHANGE:
594         // A6.3.3 BX|BLX <Rm>
595         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[Rn | (H2 ? 8:0)]);
596         return;
597 
598       case DATA_FORMAT1:
599         // A6.4.3  <Rd>, <Rn>, <Rm>
600         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, r%d", Rd, Rn, Rm);
601         return;
602       case DATA_FORMAT2:
603         // A6.4.3  <Rd>, <Rn>, #3_bit_immed
604         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rd, Rn, Rm);
605         return;
606       case DATA_FORMAT3:
607         // A6.4.3  <Rd>|<Rn>, #imm8
608         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, #0x%x", (OpCode >> 8) & 7, OpCode & 0xff);
609         return;
610       case DATA_FORMAT4:
611         // A6.4.3  <Rd>|<Rm>, #immed_5
612         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rn, Rd, (OpCode >> 6) & 0x1f);
613         return;
614       case DATA_FORMAT5:
615         // A6.4.3  <Rd>|<Rm>, <Rm>|<Rs>
616         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d", Rd, Rn);
617         return;
618       case DATA_FORMAT6_SP:
619         // A6.4.3  <Rd>, <reg>, #<8_Bit_immed>
620         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, sp, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2);
621         return;
622       case DATA_FORMAT6_PC:
623         // A6.4.3  <Rd>, <reg>, #<8_Bit_immed>
624         AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, pc, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2);
625         return;
626       case DATA_FORMAT7:
627         // A6.4.3  SP, SP, #<7_Bit_immed>
628         AsciiSPrint (&Buf[Offset], Size - Offset, " sp, sp, 0x%x", (OpCode & 0x7f)*4);
629         return;
630       case DATA_FORMAT8:
631         // A6.4.3  <Rd>|<Rn>, <Rm>
632         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd | (H1 ? 8:0)], gReg[Rn | (H2 ? 8:0)]);
633         return;
634 
635       case CPS_FORMAT:
636         // A7.1.24
637         AsciiSPrint (&Buf[Offset], Size - Offset, "%a %a%a%a", imod ? "ID":"IE", ((OpCode & BIT2) == 0) ? "":"a",  ((OpCode & BIT1) == 0) ? "":"i", ((OpCode & BIT0) == 0) ? "":"f");
638         return;
639 
640       case ENDIAN_FORMAT:
641         // A7.1.24
642         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", (OpCode & BIT3) == 0 ? "LE":"BE");
643         return;
644 
645       case DATA_CBZ:
646         // CB{N}Z <Rn>, <Lable>
647         Target = ((OpCode >> 2) & 0x3e) | (((OpCode & BIT9) == BIT9) ? BIT6 : 0);
648         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[Rd], PC + 4 + Target);
649         return;
650 
651       case ADR_FORMAT:
652         // ADR <Rd>, <Label>
653         Target = (OpCode & 0xff) << 2;
654         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[(OpCode >> 8) & 7], PCAlign4 (PC) + Target);
655         return;
656 
657       case IT_BLOCK:
658         // ITSTATE = cond:mask   OpCode[7:4]:OpCode[3:0]
659         // ITSTATE[7:5] == cond[3:1]
660         // ITSTATE[4] == 1st Instruction cond[0]
661         // ITSTATE[3] == 2st Instruction cond[0]
662         // ITSTATE[2] == 3st Instruction cond[0]
663         // ITSTATE[1] == 4st Instruction cond[0]
664         // ITSTATE[0] == 1 4 instruction IT block. 0 means 0,1,2 or 3 instructions
665         // 1st one  in ITSTATE low bits defines the number of instructions
666         Mask = (OpCode & 0xf);
667         if ((Mask & 0x1) == 0x1) {
668           *ItBlock = 4;
669           Offset +=  AsciiSPrint (&Buf[Offset], Size - Offset, "%a%a%a", (Mask & BIT3)?"T":"E", (Mask & BIT2)?"T":"E", (Mask & BIT1)?"T":"E");
670         } else if ((OpCode & 0x3) == 0x2) {
671           *ItBlock = 3;
672           Offset +=  AsciiSPrint (&Buf[Offset], Size - Offset, "%a%a", (Mask & BIT3)?"T":"E", (Mask & BIT2)?"T":"E");
673         } else if ((OpCode & 0x7) == 0x4) {
674           *ItBlock = 2;
675           Offset +=  AsciiSPrint (&Buf[Offset], Size - Offset, "%a", (Mask & BIT3)?"T":"E");
676         } else if ((OpCode & 0xf) == 0x8) {
677           *ItBlock = 1;
678         }
679         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gCondition[(OpCode >> 4) & 0xf]);
680         return;
681       }
682     }
683   }
684 
685 
686   // Thumb2 are 32-bit instructions
687   *OpCodePtrPtr += 1;
688   Rt  = (OpCode32 >> 12) & 0xf;
689   Rt2 = (OpCode32 >> 8) & 0xf;
690   Rd  = (OpCode32 >> 8) & 0xf;
691   Rm  = (OpCode32 & 0xf);
692   Rn  = (OpCode32 >> 16) & 0xf;
693   for (Index = 0; Index < sizeof (gOpThumb2)/sizeof (THUMB_INSTRUCTIONS); Index++) {
694     if ((OpCode32 & gOpThumb2[Index].Mask) == gOpThumb2[Index].OpCode) {
695       if (Extended) {
696         Offset = AsciiSPrint (Buf, Size, "0x%04x   %-6a", OpCode32, gOpThumb2[Index].Start);
697       } else {
698         Offset = AsciiSPrint (Buf, Size, "   %-6a", gOpThumb2[Index].Start);
699       }
700       switch (gOpThumb2[Index].AddressMode) {
701       case B_T3:
702         Cond = gCondition[(OpCode32 >> 22) & 0xf];
703         Buf[Offset-5] = *Cond++;
704         Buf[Offset-4] = *Cond;
705         // S:J2:J1:imm6:imm11:0
706         Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3f000);
707         Target |= ((OpCode32 & BIT11) == BIT11)? BIT19 : 0;  // J2
708         Target |= ((OpCode32 & BIT13) == BIT13)? BIT18 : 0;  // J1
709         Target |= ((OpCode32 & BIT26) == BIT26)? BIT20 : 0;  // S
710         Target = SignExtend32 (Target, BIT20);
711         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target);
712         return;
713       case B_T4:
714         // S:I1:I2:imm10:imm11:0
715         Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3ff000);
716         S  = (OpCode32 & BIT26) == BIT26;
717         J1 = (OpCode32 & BIT13) == BIT13;
718         J2 = (OpCode32 & BIT11) == BIT11;
719         Target |= (!(J2 ^ S) ? BIT22 : 0);  // I2
720         Target |= (!(J1 ^ S) ? BIT23 : 0);  // I1
721         Target |= (S ? BIT24 : 0);  // S
722         Target = SignExtend32 (Target, BIT24);
723         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target);
724         return;
725 
726       case BL_T2:
727         // BLX  S:I1:I2:imm10:imm11:0
728         Target = ((OpCode32 << 1) & 0xffc) + ((OpCode32 >> 4) & 0x3ff000);
729         S  = (OpCode32 & BIT26) == BIT26;
730         J1 = (OpCode32 & BIT13) == BIT13;
731         J2 = (OpCode32 & BIT11) == BIT11;
732         Target |= (!(J2 ^ S) ? BIT23 : 0);  // I2
733         Target |= (!(J1 ^ S) ? BIT24 : 0);  // I1
734         Target |= (S ? BIT25 : 0);  // S
735         Target = SignExtend32 (Target, BIT25);
736         AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PCAlign4 (PC) + Target);
737         return;
738 
739       case POP_T2:
740         // <reglist>  some must be zero, handled in table
741         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList (OpCode32 & 0xffff));
742         return;
743 
744       case POP_T3:
745         // <register>
746         AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[(OpCode32 >> 12) & 0xf]);
747         return;
748 
749       case STM_FORMAT:
750         // <Rn>{!}, <registers>
751         W = (OpCode32 & BIT21) == BIT21;
752         AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, %a", gReg[(OpCode32 >> 16) & 0xf], W ? "!":"", ThumbMRegList (OpCode32 & 0xffff));
753         return;
754 
755       case LDM_REG_IMM12_SIGNED:
756         // <rt>, <label>
757         Target = OpCode32 & 0xfff;
758         if ((OpCode32 & BIT23) == 0) {
759           // U == 0 means subtrack, U == 1 means add
760           Target = -Target;
761         }
762         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[(OpCode32 >> 12) & 0xf], PCAlign4 (PC) + Target);
763         return;
764 
765       case LDM_REG_INDIRECT_LSL:
766         // <rt>, [<rn>, <rm> {, LSL #<imm2>]}
767         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a, %a", gReg[Rt], gReg[Rn], gReg[Rm]);
768         if (((OpCode32 >> 4) & 3) == 0) {
769           AsciiSPrint (&Buf[Offset], Size - Offset, "]");
770         } else {
771           AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL #%d]", (OpCode32 >> 4) & 3);
772         }
773         return;
774 
775       case LDM_REG_IMM12:
776         // <rt>, [<rn>, {, #<imm12>]}
777         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);
778         if ((OpCode32 & 0xfff) == 0) {
779           AsciiSPrint (&Buf[Offset], Size - Offset, "]");
780         } else {
781           AsciiSPrint (&Buf[Offset], Size - Offset, ", #0x%x]", OpCode32 & 0xfff);
782         }
783         return;
784 
785       case LDM_REG_IMM8:
786         // <rt>, [<rn>, {, #<imm8>}]{!}
787         W = (OpCode32 & BIT8) == BIT8;
788         U = (OpCode32 & BIT9) == BIT9;
789         P = (OpCode32 & BIT10) == BIT10;
790         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);
791         if (P) {
792           if ((OpCode32 & 0xff) == 0) {
793             AsciiSPrint (&Buf[Offset], Size - Offset, "]%a", W?"!":"");
794           } else {
795             AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-" , OpCode32 & 0xff, W?"!":"");
796           }
797         } else {
798           AsciiSPrint (&Buf[Offset], Size - Offset, "], #%a0x%x", U?"":"-", OpCode32 & 0xff);
799         }
800         return;
801 
802       case LDRD_REG_IMM8_SIGNED:
803         // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
804         P = (OpCode32 & BIT24) == BIT24;  // index = P
805         U = (OpCode32 & BIT23) == BIT23;
806         W = (OpCode32 & BIT21) == BIT21;
807         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, [%a", gReg[Rt], gReg[Rt2], gReg[Rn]);
808         if (P) {
809           if ((OpCode32 & 0xff) == 0) {
810             AsciiSPrint (&Buf[Offset], Size - Offset, "]");
811           } else {
812             AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-", (OpCode32 & 0xff) << 2, W?"!":"");
813           }
814         } else {
815           if ((OpCode32 & 0xff) != 0) {
816             AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x", U?"":"-", (OpCode32 & 0xff) << 2);
817           }
818         }
819         return;
820 
821       case LDRD_REG_IMM8:
822         // LDRD <rt>, <rt2>, <label>
823         Target = (OpCode32 & 0xff) << 2;
824         if ((OpCode32 & BIT23) == 0) {
825           // U == 0 means subtrack, U == 1 means add
826           Target = -Target;
827         }
828         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rt], gReg[Rt2], PC + 4 + Target);
829         return;
830 
831       case LDREXB:
832         // LDREXB <Rt>, [Rn]
833         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a]", gReg[Rt], gReg[Rn]);
834         return;
835 
836       case LDREXD:
837         // LDREXD <Rt>, <Rt2>, [<Rn>]
838         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, [%a]", gReg[Rt], gReg[Rt2], gReg[Rn]);
839         return;
840 
841       case SRS_FORMAT:
842         // SP{!}, #<mode>
843         W = (OpCode32 & BIT21) == BIT21;
844         AsciiSPrint (&Buf[Offset], Size - Offset, " SP%a, #0x%x", W?"!":"", OpCode32 & 0x1f);
845         return;
846 
847       case RFE_FORMAT:
848         // <Rn>{!}
849         W = (OpCode32 & BIT21) == BIT21;
850         AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, #0x%x", gReg[Rn], W?"!":"");
851         return;
852 
853       case ADD_IMM12:
854         // ADD{S} <Rd>, <Rn>, #<const>   i:imm3:imm8
855         if ((OpCode32 & BIT20) == BIT20) {
856           Buf[Offset - 3] = 'S';  // assume %-6a
857         }
858         Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
859         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #0x%x", gReg[Rd], gReg[Rn], Target);
860         return;
861 
862       case ADD_IMM12_1REG:
863         // MOV{S} <Rd>, #<const>   i:imm3:imm8
864         if ((OpCode32 & BIT20) == BIT20) {
865           Buf[Offset - 3] = 'S';  // assume %-6a
866         }
867         Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
868         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rd], Target);
869         return;
870 
871       case THUMB2_IMM16:
872         // MOVW <Rd>, #<const>   i:imm3:imm8
873         Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
874         Target |= ((OpCode32 >> 4) & 0xf0000);
875         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rd], Target);
876         return;
877 
878       case ADD_IMM5:
879         // ADC{S}  <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
880         if ((OpCode32 & BIT20) == BIT20) {
881           Buf[Offset - 3] = 'S';  // assume %-6a
882         }
883         Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
884         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm]);
885         if (Target != 0) {
886           AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
887         }
888         return;
889 
890       case ADD_IMM5_2REG:
891         // CMP  <Rn>, <Rm> {,LSL #<const>} imm3:imm2
892         Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
893         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rn], gReg[Rm]);
894         if (Target != 0) {
895           AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
896         }
897 
898 
899       case ASR_IMM5:
900         // ARS  <Rd>, <Rm> #<const>} imm3:imm2
901         if ((OpCode32 & BIT20) == BIT20) {
902           Buf[Offset - 3] = 'S';  // assume %-6a
903         }
904         Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
905         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a #%d", gReg[Rd], gReg[Rm], Target);
906         return;
907 
908       case ASR_3REG:
909         // ARS  <Rd>, <Rn>, <Rm>
910         if ((OpCode32 & BIT20) == BIT20) {
911           Buf[Offset - 3] = 'S';  // assume %-6a
912         }
913         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a %a", gReg[Rd], gReg[Rn], gReg[Rm]);
914         return;
915 
916       case ADR_THUMB2:
917         // ADDR <Rd>, <label>
918         Target = (OpCode32 & 0xff) | ((OpCode32 >> 8) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
919         if ((OpCode & (BIT23 | BIT21)) == (BIT23 | BIT21)) {
920           Target = PCAlign4 (PC) - Target;
921         } else {
922           Target = PCAlign4 (PC) + Target;
923         }
924         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, 0x%08x", gReg[Rd], Target);
925         return;
926 
927       case CMN_THUMB2:
928         // CMN <Rn>, #<const>}
929         Target = (OpCode32 & 0xff) | ((OpCode >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
930         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rn], Target);
931         return;
932 
933       case BFC_THUMB2:
934         // BFI <Rd>, <Rn>, #<lsb>, #<width>
935         msbit = OpCode32 & 0x1f;
936         lsbit = ((OpCode32 >> 6) & 3) | ((OpCode >> 10) &  0x1c);
937         if ((Rn == 0xf) & (AsciiStrCmp (gOpThumb2[Index].Start, "BFC") == 0)){
938           // BFC <Rd>, #<lsb>, #<width>
939           AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #%d, #%d", gReg[Rd], lsbit, msbit - lsbit + 1);
940         } else if (AsciiStrCmp (gOpThumb2[Index].Start, "BFI") == 0) {
941           AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], lsbit, msbit - lsbit + 1);
942         } else {
943           AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], lsbit, msbit + 1);
944         }
945         return;
946 
947       case CPD_THUMB2:
948         // <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
949         coproc = (OpCode32 >> 8)  & 0xf;
950         opc1   = (OpCode32 >> 20) & 0xf;
951         opc2   = (OpCode32 >> 5)  & 0x7;
952         CRd    = (OpCode32 >> 12) & 0xf;
953         CRn    = (OpCode32 >> 16) & 0xf;
954         CRm    = OpCode32 & 0xf;
955         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,c%d,c%d,c%d", coproc, opc1, CRd, CRn, CRm);
956         if (opc2 != 0) {
957           AsciiSPrint (&Buf[Offset], Size - Offset, ",#%d,", opc2);
958         }
959         return;
960 
961       case MRC_THUMB2:
962         // MRC  <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
963         coproc = (OpCode32 >> 8)  & 0xf;
964         opc1   = (OpCode32 >> 20) & 0xf;
965         opc2   = (OpCode32 >> 5)  & 0x7;
966         CRn    = (OpCode32 >> 16) & 0xf;
967         CRm    = OpCode32 & 0xf;
968         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,%a,c%d,c%d", coproc, opc1, gReg[Rt], CRn, CRm);
969         if (opc2 != 0) {
970           AsciiSPrint (&Buf[Offset], Size - Offset, ",#%d,", opc2);
971         }
972         return;
973 
974       case MRRC_THUMB2:
975         // MRC  <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>,<opc2>
976         coproc = (OpCode32 >> 8)  & 0xf;
977         opc1   = (OpCode32 >> 20) & 0xf;
978         CRn    = (OpCode32 >> 16) & 0xf;
979         CRm    = OpCode32 & 0xf;
980         Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,%a,%a,c%d", coproc, opc1, gReg[Rt], gReg[Rt2], CRm);
981         return;
982 
983       case THUMB2_2REGS:
984         // <Rd>, <Rm>
985         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd], gReg[Rm]);
986         return;
987 
988       case THUMB2_4REGS:
989         // <Rd>, <Rn>, <Rm>, <Ra>
990         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm], gReg[Rt]);
991         return;
992 
993       case THUMB2_MRS:
994         // MRS <Rd>, CPSR
995         AsciiSPrint (&Buf[Offset], Size - Offset, " %a, CPSR", gReg[Rd]);
996         return;
997 
998       case THUMB2_MSR:
999         // MRS CPSR_<fields>, <Rd>
1000         Target = (OpCode32 >> 10) & 3;
1001         AsciiSPrint (&Buf[Offset], Size - Offset, " CPSR_%a%a, %a", (Target & 2) == 0 ? "":"f", (Target & 1) == 0 ? "":"s", gReg[Rd]);
1002         return;
1003 
1004       case THUMB2_NO_ARGS:
1005       default:
1006         break;
1007       }
1008     }
1009   }
1010 
1011   AsciiSPrint (Buf, Size, "0x%08x", OpCode32);
1012 }
1013 
1014 
1015 
1016 VOID
1017 DisassembleArmInstruction (
1018   IN  UINT32    **OpCodePtr,
1019   OUT CHAR8     *Buf,
1020   OUT UINTN     Size,
1021   IN  BOOLEAN   Extended
1022   );
1023 
1024 
1025 /**
1026   Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
1027   point to next instructin.
1028 
1029   We cheat and only decode instructions that access
1030   memory. If the instruction is not found we dump the instruction in hex.
1031 
1032   @param  OpCodePtrPtr  Pointer to pointer of ARM Thumb instruction to disassemble.
1033   @param  Thumb         TRUE for Thumb(2), FALSE for ARM instruction stream
1034   @param  Extended      TRUE dump hex for instruction too.
1035   @param  ItBlock       Size of IT Block
1036   @param  Buf           Buffer to sprintf disassembly into.
1037   @param  Size          Size of Buf in bytes.
1038 
1039 **/
1040 VOID
DisassembleInstruction(IN UINT8 ** OpCodePtr,IN BOOLEAN Thumb,IN BOOLEAN Extended,IN OUT UINT32 * ItBlock,OUT CHAR8 * Buf,OUT UINTN Size)1041 DisassembleInstruction (
1042   IN  UINT8     **OpCodePtr,
1043   IN  BOOLEAN   Thumb,
1044   IN  BOOLEAN   Extended,
1045   IN OUT UINT32 *ItBlock,
1046   OUT CHAR8     *Buf,
1047   OUT UINTN     Size
1048   )
1049 {
1050   if (Thumb) {
1051     DisassembleThumbInstruction ((UINT16 **)OpCodePtr, Buf, Size, ItBlock, Extended);
1052   } else {
1053     DisassembleArmInstruction ((UINT32 **)OpCodePtr, Buf, Size, Extended);
1054   }
1055 }
1056 
1057