]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/ArmDisassemblerLib/ThumbDisassembler.c
b665132d69bf26e4bd922e9c71104a6b9bc71b43
[mirror_edk2.git] / ArmPkg / Library / ArmDisassemblerLib / ThumbDisassembler.c
1 /** @file
2 Thumb Disassembler. 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 instructions
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 *
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
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 executing. So you pass
451 // in the instruction address and you get back the aligned answer
452 //
453 UINT32
454 PCAlign4 (
455 IN UINT32 Data
456 )
457 {
458 return (Data + 4) & 0xfffffffc;
459 }
460
461 /**
462 Place a disassembly of **OpCodePtr into buffer, and update OpCodePtr to
463 point to next instruction.
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
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 disassembly of **OpCodePtr into buffer, and update OpCodePtr to
1027 point to next instruction.
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
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