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