]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/ArmDisassemblerLib/ThumbDisassembler.c
3129ec6b92701feff14a3067330c0e3a5ffc1199
[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 Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
13
14 SPDX-License-Identifier: BSD-2-Clause-Patent
15
16 **/
17
18 #include <Base.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/PrintLib.h>
22
23 extern CHAR8 *gCondition[];
24
25 extern CHAR8 *gReg[];
26
27 // Thumb address modes
28 #define LOAD_STORE_FORMAT1 1
29 #define LOAD_STORE_FORMAT1_H 101
30 #define LOAD_STORE_FORMAT1_B 111
31 #define LOAD_STORE_FORMAT2 2
32 #define LOAD_STORE_FORMAT3 3
33 #define LOAD_STORE_FORMAT4 4
34 #define LOAD_STORE_MULTIPLE_FORMAT1 5
35 #define PUSH_FORMAT 6
36 #define POP_FORMAT 106
37 #define IMMED_8 7
38 #define CONDITIONAL_BRANCH 8
39 #define UNCONDITIONAL_BRANCH 9
40 #define UNCONDITIONAL_BRANCH_SHORT 109
41 #define BRANCH_EXCHANGE 10
42 #define DATA_FORMAT1 11
43 #define DATA_FORMAT2 12
44 #define DATA_FORMAT3 13
45 #define DATA_FORMAT4 14
46 #define DATA_FORMAT5 15
47 #define DATA_FORMAT6_SP 16
48 #define DATA_FORMAT6_PC 116
49 #define DATA_FORMAT7 17
50 #define DATA_FORMAT8 19
51 #define CPS_FORMAT 20
52 #define ENDIAN_FORMAT 21
53 #define DATA_CBZ 22
54 #define ADR_FORMAT 23
55 #define IT_BLOCK 24
56
57 // Thumb2 address modes
58 #define B_T3 200
59 #define B_T4 201
60 #define BL_T2 202
61 #define POP_T2 203
62 #define POP_T3 204
63 #define STM_FORMAT 205
64 #define LDM_REG_IMM12_SIGNED 206
65 #define LDM_REG_IMM12_LSL 207
66 #define LDM_REG_IMM8 208
67 #define LDM_REG_IMM12 209
68 #define LDM_REG_INDIRECT_LSL 210
69 #define LDM_REG_IMM8_SIGNED 211
70 #define LDRD_REG_IMM8 212
71 #define LDREXB 213
72 #define LDREXD 214
73 #define SRS_FORMAT 215
74 #define RFE_FORMAT 216
75 #define LDRD_REG_IMM8_SIGNED 217
76 #define ADD_IMM12 218
77 #define ADD_IMM5 219
78 #define ADR_THUMB2 220
79 #define CMN_THUMB2 221
80 #define ASR_IMM5 222
81 #define ASR_3REG 223
82 #define BFC_THUMB2 224
83 #define CDP_THUMB2 225
84 #define THUMB2_NO_ARGS 226
85 #define THUMB2_2REGS 227
86 #define ADD_IMM5_2REG 228
87 #define CPD_THUMB2 229
88 #define THUMB2_4REGS 230
89 #define ADD_IMM12_1REG 231
90 #define THUMB2_IMM16 232
91 #define MRC_THUMB2 233
92 #define MRRC_THUMB2 234
93 #define THUMB2_MRS 235
94 #define THUMB2_MSR 236
95
96
97
98
99 typedef struct {
100 CHAR8 *Start;
101 UINT32 OpCode;
102 UINT32 Mask;
103 UINT32 AddressMode;
104 } THUMB_INSTRUCTIONS;
105
106 THUMB_INSTRUCTIONS gOpThumb[] = {
107 // Thumb 16-bit instructions
108 // Op Mask Format
109 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5 }, // ADC <Rndn>, <Rm>
110 { "ADR", 0xa000, 0xf800, ADR_FORMAT }, // ADR <Rd>, <label>
111 { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2 },
112 { "ADD" , 0x3000, 0xf800, DATA_FORMAT3 },
113 { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1 },
114 { "ADD" , 0x4400, 0xff00, DATA_FORMAT8 }, // A8.6.9
115 { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC },
116 { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP },
117 { "ADD" , 0xb000, 0xff80, DATA_FORMAT7 },
118
119 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5 },
120
121 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4 },
122 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5 },
123
124 { "B" , 0xd000, 0xf000, CONDITIONAL_BRANCH },
125 { "B" , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT },
126 { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE },
127 { "BX" , 0x4700, 0xff87, BRANCH_EXCHANGE },
128
129 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5 },
130 { "BKPT", 0xdf00, 0xff00, IMMED_8 },
131 { "CBZ", 0xb100, 0xfd00, DATA_CBZ },
132 { "CBNZ", 0xb900, 0xfd00, DATA_CBZ },
133 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5 },
134
135 { "CMP" , 0x2800, 0xf800, DATA_FORMAT3 },
136 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5 },
137 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8 },
138
139 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT },
140 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
141 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5 },
142
143 { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
144 { "LDR" , 0x6800, 0xf800, LOAD_STORE_FORMAT1 }, // LDR <Rt>, [<Rn> {,#<imm>}]
145 { "LDR" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 }, // STR <Rt>, [<Rn>, <Rm>]
146 { "LDR" , 0x4800, 0xf800, LOAD_STORE_FORMAT3 },
147 { "LDR" , 0x9800, 0xf800, LOAD_STORE_FORMAT4 }, // LDR <Rt>, [SP, #<imm>]
148 { "LDRB" , 0x7800, 0xf800, LOAD_STORE_FORMAT1_B },
149 { "LDRB" , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2 }, // STR <Rt>, [<Rn>, <Rm>]
150 { "LDRH" , 0x8800, 0xf800, LOAD_STORE_FORMAT1_H },
151 { "LDRH" , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2 },
152 { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2 }, // STR <Rt>, [<Rn>, <Rm>]
153 { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2 },
154
155 { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5 }, // LSL with imm5 == 0 is a MOVS, so this must go before LSL
156 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4 },
157 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5 },
158 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4 },
159 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5 },
160 { "LSRS", 0x0800, 0xf800, DATA_FORMAT4 }, // LSRS <Rd>, <Rm>, #<imm5>
161
162 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3 },
163 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3 },
164 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
165
166 { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5 },
167 { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5 },
168 { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5 },
169 { "ORR" , 0x4300, 0xffc0, DATA_FORMAT5 },
170 { "POP" , 0xbc00, 0xfe00, POP_FORMAT },
171 { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT },
172
173 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5 },
174 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5 },
175 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5 },
176
177 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5 },
178 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5 },
179 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT },
180
181 { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
182 { "STR" , 0x6000, 0xf800, LOAD_STORE_FORMAT1 }, // STR <Rt>, [<Rn> {,#<imm>}]
183 { "STR" , 0x5000, 0xfe00, LOAD_STORE_FORMAT2 }, // STR <Rt>, [<Rn>, <Rm>]
184 { "STR" , 0x9000, 0xf800, LOAD_STORE_FORMAT4 }, // STR <Rt>, [SP, #<imm>]
185 { "STRB" , 0x7000, 0xf800, LOAD_STORE_FORMAT1_B }, // STRB <Rt>, [<Rn>, #<imm5>]
186 { "STRB" , 0x5400, 0xfe00, LOAD_STORE_FORMAT2 }, // STRB <Rt>, [<Rn>, <Rm>]
187 { "STRH" , 0x8000, 0xf800, LOAD_STORE_FORMAT1_H }, // STRH <Rt>, [<Rn>{,#<imm>}]
188 { "STRH" , 0x5200, 0xfe00, LOAD_STORE_FORMAT2 }, // STRH <Rt>, [<Rn>, <Rm>]
189
190 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2 },
191 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3 },
192 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1 },
193 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7 },
194
195 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5 },
196
197 { "SWI" , 0xdf00, 0xff00, IMMED_8 },
198 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5 },
199 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5 },
200 { "TST" , 0x4200, 0xffc0, DATA_FORMAT5 },
201 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5 },
202 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5 },
203
204 { "IT", 0xbf00, 0xff00, IT_BLOCK }
205
206 };
207
208 THUMB_INSTRUCTIONS gOpThumb2[] = {
209 //Instruct OpCode OpCode Mask Addressig Mode
210
211 { "ADR", 0xf2af0000, 0xfbff8000, ADR_THUMB2 }, // ADDR <Rd>, <label> ;Needs to go before ADDW
212 { "CMN", 0xf1100f00, 0xfff08f00, CMN_THUMB2 }, // CMN <Rn>, #<const> ;Needs to go before ADD
213 { "CMN", 0xeb100f00, 0xfff08f00, ADD_IMM5_2REG }, // CMN <Rn>, <Rm> {,<shift> #<const>}
214 { "CMP", 0xf1a00f00, 0xfff08f00, CMN_THUMB2 }, // CMP <Rn>, #<const>
215 { "TEQ", 0xf0900f00, 0xfff08f00, CMN_THUMB2 }, // CMP <Rn>, #<const>
216 { "TEQ", 0xea900f00, 0xfff08f00, ADD_IMM5_2REG }, // CMN <Rn>, <Rm> {,<shift> #<const>}
217 { "TST", 0xf0100f00, 0xfff08f00, CMN_THUMB2 }, // CMP <Rn>, #<const>
218 { "TST", 0xea100f00, 0xfff08f00, ADD_IMM5_2REG }, // TST <Rn>, <Rm> {,<shift> #<const>}
219
220 { "MOV", 0xf04f0000, 0xfbef8000, ADD_IMM12_1REG }, // MOV <Rd>, #<const>
221 { "MOVW", 0xf2400000, 0xfbe08000, THUMB2_IMM16 }, // MOVW <Rd>, #<const>
222 { "MOVT", 0xf2c00000, 0xfbe08000, THUMB2_IMM16 }, // MOVT <Rd>, #<const>
223
224 { "ADC", 0xf1400000, 0xfbe08000, ADD_IMM12 }, // ADC{S} <Rd>, <Rn>, #<const>
225 { "ADC", 0xeb400000, 0xffe08000, ADD_IMM5 }, // ADC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
226 { "ADD", 0xf1000000, 0xfbe08000, ADD_IMM12 }, // ADD{S} <Rd>, <Rn>, #<const>
227 { "ADD", 0xeb000000, 0xffe08000, ADD_IMM5 }, // ADD{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
228 { "ADDW", 0xf2000000, 0xfbe08000, ADD_IMM12 }, // ADDW{S} <Rd>, <Rn>, #<const>
229 { "AND", 0xf0000000, 0xfbe08000, ADD_IMM12 }, // AND{S} <Rd>, <Rn>, #<const>
230 { "AND", 0xea000000, 0xffe08000, ADD_IMM5 }, // AND{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
231 { "BIC", 0xf0200000, 0xfbe08000, ADD_IMM12 }, // BIC{S} <Rd>, <Rn>, #<const>
232 { "BIC", 0xea200000, 0xffe08000, ADD_IMM5 }, // BIC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
233 { "EOR", 0xf0800000, 0xfbe08000, ADD_IMM12 }, // EOR{S} <Rd>, <Rn>, #<const>
234 { "EOR", 0xea800000, 0xffe08000, ADD_IMM5 }, // EOR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
235 { "ORN", 0xf0600000, 0xfbe08000, ADD_IMM12 }, // ORN{S} <Rd>, <Rn>, #<const>
236 { "ORN", 0xea600000, 0xffe08000, ADD_IMM5 }, // ORN{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
237 { "ORR", 0xf0400000, 0xfbe08000, ADD_IMM12 }, // ORR{S} <Rd>, <Rn>, #<const>
238 { "ORR", 0xea400000, 0xffe08000, ADD_IMM5 }, // ORR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
239 { "RSB", 0xf1c00000, 0xfbe08000, ADD_IMM12 }, // RSB{S} <Rd>, <Rn>, #<const>
240 { "RSB", 0xebc00000, 0xffe08000, ADD_IMM5 }, // RSB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
241 { "SBC", 0xf1600000, 0xfbe08000, ADD_IMM12 }, // SBC{S} <Rd>, <Rn>, #<const>
242 { "SBC", 0xeb600000, 0xffe08000, ADD_IMM5 }, // SBC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
243 { "SUB", 0xf1a00000, 0xfbe08000, ADD_IMM12 }, // SUB{S} <Rd>, <Rn>, #<const>
244 { "SUB", 0xeba00000, 0xffe08000, ADD_IMM5 }, // SUB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
245
246 { "ASR", 0xea4f0020, 0xffef8030, ASR_IMM5 }, // ARS <Rd>, <Rm> #<const>} imm3:imm2
247 { "ASR", 0xfa40f000, 0xffe0f0f0, ASR_3REG }, // ARS <Rd>, <Rn>, <Rm>
248 { "LSR", 0xea4f0010, 0xffef8030, ASR_IMM5 }, // LSR <Rd>, <Rm> #<const>} imm3:imm2
249 { "LSR", 0xfa20f000, 0xffe0f0f0, ASR_3REG }, // LSR <Rd>, <Rn>, <Rm>
250 { "ROR", 0xea4f0030, 0xffef8030, ASR_IMM5 }, // ROR <Rd>, <Rm> #<const>} imm3:imm2
251 { "ROR", 0xfa60f000, 0xffe0f0f0, ASR_3REG }, // ROR <Rd>, <Rn>, <Rm>
252
253 { "BFC", 0xf36f0000, 0xffff8010, BFC_THUMB2 }, // BFC <Rd>, #<lsb>, #<width>
254 { "BIC", 0xf3600000, 0xfff08010, BFC_THUMB2 }, // BIC <Rn>, <Rd>, #<lsb>, #<width>
255 { "SBFX", 0xf3400000, 0xfff08010, BFC_THUMB2 }, // SBFX <Rn>, <Rd>, #<lsb>, #<width>
256 { "UBFX", 0xf3c00000, 0xfff08010, BFC_THUMB2 }, // UBFX <Rn>, <Rd>, #<lsb>, #<width>
257
258 { "CPD", 0xee000000, 0xff000010, CPD_THUMB2 }, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
259 { "CPD2", 0xfe000000, 0xff000010, CPD_THUMB2 }, // CPD <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
260
261 { "MRC", 0xee100000, 0xff100000, MRC_THUMB2 }, // MRC <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
262 { "MRC2", 0xfe100000, 0xff100000, MRC_THUMB2 }, // MRC2 <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
263 { "MRRC", 0xec500000, 0xfff00000, MRRC_THUMB2 }, // MRRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
264 { "MRRC2", 0xfc500000, 0xfff00000, MRRC_THUMB2 }, // MRR2 <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>
265
266 { "MRS", 0xf3ef8000, 0xfffff0ff, THUMB2_MRS }, // MRS <Rd>, CPSR
267 { "MSR", 0xf3808000, 0xfff0fcff, THUMB2_MSR }, // MSR CPSR_fs, <Rn>
268
269 { "CLREX", 0xf3bf8f2f, 0xfffffff, THUMB2_NO_ARGS }, // CLREX
270
271 { "CLZ", 0xfab0f080, 0xfff0f0f0, THUMB2_2REGS }, // CLZ <Rd>,<Rm>
272 { "MOV", 0xec4f0000, 0xfff0f0f0, THUMB2_2REGS }, // MOV <Rd>,<Rm>
273 { "MOVS", 0xec5f0000, 0xfff0f0f0, THUMB2_2REGS }, // MOVS <Rd>,<Rm>
274 { "RBIT", 0xfb90f0a0, 0xfff0f0f0, THUMB2_2REGS }, // RBIT <Rd>,<Rm>
275 { "REV", 0xfb90f080, 0xfff0f0f0, THUMB2_2REGS }, // REV <Rd>,<Rm>
276 { "REV16", 0xfa90f090, 0xfff0f0f0, THUMB2_2REGS }, // REV16 <Rd>,<Rm>
277 { "REVSH", 0xfa90f0b0, 0xfff0f0f0, THUMB2_2REGS }, // REVSH <Rd>,<Rm>
278 { "RRX", 0xea4f0030, 0xfffff0f0, THUMB2_2REGS }, // RRX <Rd>,<Rm>
279 { "RRXS", 0xea5f0030, 0xfffff0f0, THUMB2_2REGS }, // RRXS <Rd>,<Rm>
280
281 { "MLA", 0xfb000000, 0xfff000f0, THUMB2_4REGS }, // MLA <Rd>, <Rn>, <Rm>, <Ra>
282 { "MLS", 0xfb000010, 0xfff000f0, THUMB2_4REGS }, // MLA <Rd>, <Rn>, <Rm>, <Ra>
283
284
285 { "SMLABB", 0xfb100000, 0xfff000f0, THUMB2_4REGS }, // SMLABB <Rd>, <Rn>, <Rm>, <Ra>
286 { "SMLABT", 0xfb100010, 0xfff000f0, THUMB2_4REGS }, // SMLABT <Rd>, <Rn>, <Rm>, <Ra>
287 { "SMLABB", 0xfb100020, 0xfff000f0, THUMB2_4REGS }, // SMLATB <Rd>, <Rn>, <Rm>, <Ra>
288 { "SMLATT", 0xfb100030, 0xfff000f0, THUMB2_4REGS }, // SMLATT <Rd>, <Rn>, <Rm>, <Ra>
289 { "SMLAWB", 0xfb300000, 0xfff000f0, THUMB2_4REGS }, // SMLAWB <Rd>, <Rn>, <Rm>, <Ra>
290 { "SMLAWT", 0xfb300010, 0xfff000f0, THUMB2_4REGS }, // SMLAWT <Rd>, <Rn>, <Rm>, <Ra>
291 { "SMLSD", 0xfb400000, 0xfff000f0, THUMB2_4REGS }, // SMLSD <Rd>, <Rn>, <Rm>, <Ra>
292 { "SMLSDX", 0xfb400010, 0xfff000f0, THUMB2_4REGS }, // SMLSDX <Rd>, <Rn>, <Rm>, <Ra>
293 { "SMMLA", 0xfb500000, 0xfff000f0, THUMB2_4REGS }, // SMMLA <Rd>, <Rn>, <Rm>, <Ra>
294 { "SMMLAR", 0xfb500010, 0xfff000f0, THUMB2_4REGS }, // SMMLAR <Rd>, <Rn>, <Rm>, <Ra>
295 { "SMMLS", 0xfb600000, 0xfff000f0, THUMB2_4REGS }, // SMMLS <Rd>, <Rn>, <Rm>, <Ra>
296 { "SMMLSR", 0xfb600010, 0xfff000f0, THUMB2_4REGS }, // SMMLSR <Rd>, <Rn>, <Rm>, <Ra>
297 { "USADA8", 0xfb700000, 0xfff000f0, THUMB2_4REGS }, // USADA8 <Rd>, <Rn>, <Rm>, <Ra>
298 { "SMLAD", 0xfb200000, 0xfff000f0, THUMB2_4REGS }, // SMLAD <Rd>, <Rn>, <Rm>, <Ra>
299 { "SMLADX", 0xfb200010, 0xfff000f0, THUMB2_4REGS }, // SMLADX <Rd>, <Rn>, <Rm>, <Ra>
300
301
302 { "B", 0xf0008000, 0xf800d000, B_T3 }, // B<c> <label>
303 { "B", 0xf0009000, 0xf800d000, B_T4 }, // B<c> <label>
304 { "BL", 0xf000d000, 0xf800d000, B_T4 }, // BL<c> <label>
305 { "BLX", 0xf000c000, 0xf800d000, BL_T2 }, // BLX<c> <label>
306
307 { "POP", 0xe8bd0000, 0xffff2000, POP_T2 }, // POP <registers>
308 { "POP", 0xf85d0b04, 0xffff0fff, POP_T3 }, // POP <register>
309 { "PUSH", 0xe8ad0000, 0xffffa000, POP_T2 }, // PUSH <registers>
310 { "PUSH", 0xf84d0d04, 0xffff0fff, POP_T3 }, // PUSH <register>
311 { "STM" , 0xe8800000, 0xffd0a000, STM_FORMAT }, // STM <Rn>{!},<registers>
312 { "STMDB", 0xe9800000, 0xffd0a000, STM_FORMAT }, // STMDB <Rn>{!},<registers>
313 { "LDM" , 0xe8900000, 0xffd02000, STM_FORMAT }, // LDM <Rn>{!},<registers>
314 { "LDMDB", 0xe9100000, 0xffd02000, STM_FORMAT }, // LDMDB <Rn>{!},<registers>
315
316 { "LDR", 0xf8d00000, 0xfff00000, LDM_REG_IMM12 }, // LDR <rt>, [<rn>, {, #<imm12>]}
317 { "LDRB", 0xf8900000, 0xfff00000, LDM_REG_IMM12 }, // LDRB <rt>, [<rn>, {, #<imm12>]}
318 { "LDRH", 0xf8b00000, 0xfff00000, LDM_REG_IMM12 }, // LDRH <rt>, [<rn>, {, #<imm12>]}
319 { "LDRSB", 0xf9900000, 0xfff00000, LDM_REG_IMM12 }, // LDRSB <rt>, [<rn>, {, #<imm12>]}
320 { "LDRSH", 0xf9b00000, 0xfff00000, LDM_REG_IMM12 }, // LDRSH <rt>, [<rn>, {, #<imm12>]}
321
322 { "LDR", 0xf85f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDR <Rt>, <label>
323 { "LDRB", 0xf81f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRB <Rt>, <label>
324 { "LDRH", 0xf83f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRH <Rt>, <label>
325 { "LDRSB", 0xf91f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRSB <Rt>, <label>
326 { "LDRSH", 0xf93f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRSB <Rt>, <label>
327
328 { "LDR", 0xf8500000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
329 { "LDRB", 0xf8100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
330 { "LDRH", 0xf8300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
331 { "LDRSB", 0xf9100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
332 { "LDRSH", 0xf9300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
333
334 { "LDR", 0xf8500800, 0xfff00800, LDM_REG_IMM8 }, // LDR <rt>, [<rn>, {, #<imm8>]}
335 { "LDRBT", 0xf8100e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRBT <rt>, [<rn>, {, #<imm8>]}
336 { "LDRHT", 0xf8300e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRHT <rt>, [<rn>, {, #<imm8>]}
337 { "LDRSB", 0xf9100800, 0xfff00800, LDM_REG_IMM8 }, // LDRHT <rt>, [<rn>, {, #<imm8>]} {!} form?
338 { "LDRSBT",0xf9100e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRHBT <rt>, [<rn>, {, #<imm8>]} {!} form?
339 { "LDRSH" ,0xf9300800, 0xfff00800, LDM_REG_IMM8 }, // LDRSH <rt>, [<rn>, {, #<imm8>]}
340 { "LDRSHT",0xf9300e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRSHT <rt>, [<rn>, {, #<imm8>]}
341 { "LDRT", 0xf8500e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRT <rt>, [<rn>, {, #<imm8>]}
342
343 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
344 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8 }, // LDRD <rt>, <rt2>, <label>
345
346 { "LDREX", 0xe8500f00, 0xfff00f00, LDM_REG_IMM8 }, // LDREX <Rt>, [Rn, {#imm8}]]
347 { "LDREXB", 0xe8d00f4f, 0xfff00fff, LDREXB }, // LDREXB <Rt>, [<Rn>]
348 { "LDREXH", 0xe8d00f5f, 0xfff00fff, LDREXB }, // LDREXH <Rt>, [<Rn>]
349
350 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // LDREXD <Rt>, <Rt2>, [<Rn>]
351
352 { "STR", 0xf8c00000, 0xfff00000, LDM_REG_IMM12 }, // STR <rt>, [<rn>, {, #<imm12>]}
353 { "STRB", 0xf8800000, 0xfff00000, LDM_REG_IMM12 }, // STRB <rt>, [<rn>, {, #<imm12>]}
354 { "STRH", 0xf8a00000, 0xfff00000, LDM_REG_IMM12 }, // STRH <rt>, [<rn>, {, #<imm12>]}
355
356 { "STR", 0xf8400000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
357 { "STRB", 0xf8000000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
358 { "STRH", 0xf8200000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
359
360 { "STR", 0xf8400800, 0xfff00800, LDM_REG_IMM8 }, // STR <rt>, [<rn>, {, #<imm8>]}
361 { "STRH", 0xf8200800, 0xfff00800, LDM_REG_IMM8 }, // STRH <rt>, [<rn>, {, #<imm8>]}
362 { "STRBT", 0xf8000e00, 0xfff00f00, LDM_REG_IMM8 }, // STRBT <rt>, [<rn>, {, #<imm8>]}
363 { "STRHT", 0xf8200e00, 0xfff00f00, LDM_REG_IMM8 }, // STRHT <rt>, [<rn>, {, #<imm8>]}
364 { "STRT", 0xf8400e00, 0xfff00f00, LDM_REG_IMM8 }, // STRT <rt>, [<rn>, {, #<imm8>]}
365
366 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
367
368 { "STREX", 0xe8400f00, 0xfff00f00, LDM_REG_IMM8 }, // STREX <Rt>, [Rn, {#imm8}]]
369 { "STREXB", 0xe8c00f4f, 0xfff00fff, LDREXB }, // STREXB <Rd>, <Rt>, [<Rn>]
370 { "STREXH", 0xe8c00f5f, 0xfff00fff, LDREXB }, // STREXH <Rd>, <Rt>, [<Rn>]
371
372 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
373
374 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT }, // SRSDB<c> SP{!},#<mode>
375 { "SRS" , 0xe98dc000, 0xffdffff0, SRS_FORMAT }, // SRS{IA}<c> SP{!},#<mode>
376 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT }, // RFEDB<c> <Rn>{!}
377 { "RFE" , 0xe990c000, 0xffd0ffff, RFE_FORMAT } // RFE{IA}<c> <Rn>{!}
378 };
379
380 CHAR8 *gShiftType[] = {
381 "LSL",
382 "LSR",
383 "ASR",
384 "ROR"
385 };
386
387 CHAR8 mThumbMregListStr[4*15 + 1];
388
389 CHAR8 *
390 ThumbMRegList (
391 UINT32 RegBitMask
392 )
393 {
394 UINTN Index, Start, End;
395 BOOLEAN First;
396
397 mThumbMregListStr[0] = '\0';
398 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "{");
399
400 for (Index = 0, First = TRUE; Index <= 15; Index++) {
401 if ((RegBitMask & (1 << Index)) != 0) {
402 Start = End = Index;
403 for (Index++; ((RegBitMask & (1 << Index)) != 0) && (Index <= 9); Index++) {
404 End = Index;
405 }
406
407 if (!First) {
408 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, ",");
409 } else {
410 First = FALSE;
411 }
412
413 if (Start == End) {
414 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, gReg[Start]);
415 } else {
416 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, gReg[Start]);
417 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "-");
418 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, gReg[End]);
419 }
420 }
421 }
422 if (First) {
423 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "ERROR");
424 }
425 AsciiStrCatS (mThumbMregListStr, sizeof mThumbMregListStr, "}");
426
427 // BugBug: Make caller pass in buffer it is cleaner
428 return mThumbMregListStr;
429 }
430
431 UINT32
432 SignExtend32 (
433 IN UINT32 Data,
434 IN UINT32 TopBit
435 )
436 {
437 if (((Data & TopBit) == 0) || (TopBit == BIT31)) {
438 return Data;
439 }
440
441 do {
442 TopBit <<= 1;
443 Data |= TopBit;
444 } while ((TopBit & BIT31) != BIT31);
445
446 return Data;
447 }
448
449 //
450 // Some instructions specify the PC is always considered aligned
451 // The PC is after the instruction that is executing. So you pass
452 // in the instruction address and you get back the aligned answer
453 //
454 UINT32
455 PcAlign4 (
456 IN UINT32 Data
457 )
458 {
459 return (Data + 4) & 0xfffffffc;
460 }
461
462 /**
463 Place a disassembly of **OpCodePtr into buffer, and update OpCodePtr to
464 point to next instruction.
465
466 We cheat and only decode instructions that access
467 memory. If the instruction is not found we dump the instruction in hex.
468
469 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
470 @param Buf Buffer to sprintf disassembly into.
471 @param Size Size of Buf in bytes.
472 @param Extended TRUE dump hex for instruction too.
473
474 **/
475 VOID
476 DisassembleThumbInstruction (
477 IN UINT16 **OpCodePtrPtr,
478 OUT CHAR8 *Buf,
479 OUT UINTN Size,
480 OUT UINT32 *ItBlock,
481 IN BOOLEAN Extended
482 )
483 {
484 UINT16 *OpCodePtr;
485 UINT16 OpCode;
486 UINT32 OpCode32;
487 UINT32 Index;
488 UINT32 Offset;
489 UINT16 Rd, Rn, Rm, Rt, Rt2;
490 BOOLEAN H1Bit; // H1
491 BOOLEAN H2Bit; // H2
492 BOOLEAN IMod; // imod
493 //BOOLEAN ItFlag;
494 UINT32 Pc, Target, MsBit, LsBit;
495 CHAR8 *Cond;
496 BOOLEAN Sign; // S
497 BOOLEAN J1Bit; // J1
498 BOOLEAN J2Bit; // J2
499 BOOLEAN Pre; // P
500 BOOLEAN UAdd; // U
501 BOOLEAN WriteBack; // 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 H1Bit = (OpCode & BIT7) != 0;
516 H2Bit = (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 | (H2Bit ? 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 | (H1Bit ? 8:0)], gReg[Rn | (H2Bit ? 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 Sign = (OpCode32 & BIT26) == BIT26;
725 J1Bit = (OpCode32 & BIT13) == BIT13;
726 J2Bit = (OpCode32 & BIT11) == BIT11;
727 Target |= (!(J2Bit ^ Sign) ? BIT22 : 0); // I2
728 Target |= (!(J1Bit ^ Sign) ? BIT23 : 0); // I1
729 Target |= (Sign ? 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 Sign = (OpCode32 & BIT26) == BIT26;
738 J1Bit = (OpCode32 & BIT13) == BIT13;
739 J2Bit = (OpCode32 & BIT11) == BIT11;
740 Target |= (!(J2Bit ^ Sign) ? BIT23 : 0); // I2
741 Target |= (!(J1Bit ^ Sign) ? BIT24 : 0); // I1
742 Target |= (Sign ? 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 WriteBack = (OpCode32 & BIT21) == BIT21;
760 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, %a", gReg[(OpCode32 >> 16) & 0xf], WriteBack ? "!":"", 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 // <rt>, [<rn>, {, #<imm8>}]{!}
795 WriteBack = (OpCode32 & BIT8) == BIT8;
796 UAdd = (OpCode32 & BIT9) == BIT9;
797 Pre = (OpCode32 & BIT10) == BIT10;
798 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);
799 if (Pre) {
800 if ((OpCode32 & 0xff) == 0) {
801 AsciiSPrint (&Buf[Offset], Size - Offset, "]%a", WriteBack?"!":"");
802 } else {
803 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", UAdd?"":"-" , OpCode32 & 0xff, WriteBack?"!":"");
804 }
805 } else {
806 AsciiSPrint (&Buf[Offset], Size - Offset, "], #%a0x%x", UAdd?"":"-", OpCode32 & 0xff);
807 }
808 return;
809
810 case LDRD_REG_IMM8_SIGNED:
811 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
812 Pre = (OpCode32 & BIT24) == BIT24; // index = P
813 UAdd = (OpCode32 & BIT23) == BIT23;
814 WriteBack = (OpCode32 & BIT21) == BIT21;
815 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, [%a", gReg[Rt], gReg[Rt2], gReg[Rn]);
816 if (Pre) {
817 if ((OpCode32 & 0xff) == 0) {
818 AsciiSPrint (&Buf[Offset], Size - Offset, "]");
819 } else {
820 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", UAdd?"":"-", (OpCode32 & 0xff) << 2, WriteBack?"!":"");
821 }
822 } else {
823 if ((OpCode32 & 0xff) != 0) {
824 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x", UAdd?"":"-", (OpCode32 & 0xff) << 2);
825 }
826 }
827 return;
828
829 case LDRD_REG_IMM8:
830 // LDRD <rt>, <rt2>, <label>
831 Target = (OpCode32 & 0xff) << 2;
832 if ((OpCode32 & BIT23) == 0) {
833 // U == 0 means subtrack, U == 1 means add
834 Target = -Target;
835 }
836 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rt], gReg[Rt2], Pc + 4 + Target);
837 return;
838
839 case LDREXB:
840 // LDREXB <Rt>, [Rn]
841 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a]", gReg[Rt], gReg[Rn]);
842 return;
843
844 case LDREXD:
845 // LDREXD <Rt>, <Rt2>, [<Rn>]
846 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, [%a]", gReg[Rt], gReg[Rt2], gReg[Rn]);
847 return;
848
849 case SRS_FORMAT:
850 // SP{!}, #<mode>
851 WriteBack = (OpCode32 & BIT21) == BIT21;
852 AsciiSPrint (&Buf[Offset], Size - Offset, " SP%a, #0x%x", WriteBack?"!":"", OpCode32 & 0x1f);
853 return;
854
855 case RFE_FORMAT:
856 // <Rn>{!}
857 WriteBack = (OpCode32 & BIT21) == BIT21;
858 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, #0x%x", gReg[Rn], WriteBack?"!":"");
859 return;
860
861 case ADD_IMM12:
862 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8
863 if ((OpCode32 & BIT20) == BIT20) {
864 Buf[Offset - 3] = 'S'; // assume %-6a
865 }
866 Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
867 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #0x%x", gReg[Rd], gReg[Rn], Target);
868 return;
869
870 case ADD_IMM12_1REG:
871 // MOV{S} <Rd>, #<const> i:imm3:imm8
872 if ((OpCode32 & BIT20) == BIT20) {
873 Buf[Offset - 3] = 'S'; // assume %-6a
874 }
875 Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
876 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rd], Target);
877 return;
878
879 case THUMB2_IMM16:
880 // MOVW <Rd>, #<const> i:imm3:imm8
881 Target = (OpCode32 & 0xff) | ((OpCode32 >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
882 Target |= ((OpCode32 >> 4) & 0xf0000);
883 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rd], Target);
884 return;
885
886 case ADD_IMM5:
887 // ADC{S} <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
888 if ((OpCode32 & BIT20) == BIT20) {
889 Buf[Offset - 3] = 'S'; // assume %-6a
890 }
891 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
892 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm]);
893 if (Target != 0) {
894 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
895 }
896 return;
897
898 case ADD_IMM5_2REG:
899 // CMP <Rn>, <Rm> {,LSL #<const>} imm3:imm2
900 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
901 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rn], gReg[Rm]);
902 if (Target != 0) {
903 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
904 }
905
906
907 case ASR_IMM5:
908 // ARS <Rd>, <Rm> #<const>} imm3:imm2
909 if ((OpCode32 & BIT20) == BIT20) {
910 Buf[Offset - 3] = 'S'; // assume %-6a
911 }
912 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
913 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a #%d", gReg[Rd], gReg[Rm], Target);
914 return;
915
916 case ASR_3REG:
917 // ARS <Rd>, <Rn>, <Rm>
918 if ((OpCode32 & BIT20) == BIT20) {
919 Buf[Offset - 3] = 'S'; // assume %-6a
920 }
921 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a %a", gReg[Rd], gReg[Rn], gReg[Rm]);
922 return;
923
924 case ADR_THUMB2:
925 // ADDR <Rd>, <label>
926 Target = (OpCode32 & 0xff) | ((OpCode32 >> 8) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
927 if ((OpCode & (BIT23 | BIT21)) == (BIT23 | BIT21)) {
928 Target = PcAlign4 (Pc) - Target;
929 } else {
930 Target = PcAlign4 (Pc) + Target;
931 }
932 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, 0x%08x", gReg[Rd], Target);
933 return;
934
935 case CMN_THUMB2:
936 // CMN <Rn>, #<const>}
937 Target = (OpCode32 & 0xff) | ((OpCode >> 4) & 0x700) | ((OpCode & BIT26) == BIT26 ? BIT11 : 0);
938 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #0x%x", gReg[Rn], Target);
939 return;
940
941 case BFC_THUMB2:
942 // BFI <Rd>, <Rn>, #<lsb>, #<width>
943 MsBit = OpCode32 & 0x1f;
944 LsBit = ((OpCode32 >> 6) & 3) | ((OpCode >> 10) & 0x1c);
945 if ((Rn == 0xf) & (AsciiStrCmp (gOpThumb2[Index].Start, "BFC") == 0)){
946 // BFC <Rd>, #<lsb>, #<width>
947 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, #%d, #%d", gReg[Rd], LsBit, MsBit - LsBit + 1);
948 } else if (AsciiStrCmp (gOpThumb2[Index].Start, "BFI") == 0) {
949 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], LsBit, MsBit - LsBit + 1);
950 } else {
951 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, #%d, #%d", gReg[Rd], gReg[Rn], LsBit, MsBit + 1);
952 }
953 return;
954
955 case CPD_THUMB2:
956 // <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2>
957 Coproc = (OpCode32 >> 8) & 0xf;
958 Opc1 = (OpCode32 >> 20) & 0xf;
959 Opc2 = (OpCode32 >> 5) & 0x7;
960 CRd = (OpCode32 >> 12) & 0xf;
961 CRn = (OpCode32 >> 16) & 0xf;
962 CRm = OpCode32 & 0xf;
963 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,c%d,c%d,c%d", Coproc, Opc1, CRd, CRn, CRm);
964 if (Opc2 != 0) {
965 AsciiSPrint (&Buf[Offset], Size - Offset, ",#%d,", Opc2);
966 }
967 return;
968
969 case MRC_THUMB2:
970 // MRC <coproc>,<opc1>,<Rt>,<CRn>,<CRm>,<opc2>
971 Coproc = (OpCode32 >> 8) & 0xf;
972 Opc1 = (OpCode32 >> 20) & 0xf;
973 Opc2 = (OpCode32 >> 5) & 0x7;
974 CRn = (OpCode32 >> 16) & 0xf;
975 CRm = OpCode32 & 0xf;
976 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,%a,c%d,c%d", Coproc, Opc1, gReg[Rt], CRn, CRm);
977 if (Opc2 != 0) {
978 AsciiSPrint (&Buf[Offset], Size - Offset, ",#%d,", Opc2);
979 }
980 return;
981
982 case MRRC_THUMB2:
983 // MRC <coproc>,<opc1>,<Rt>,<Rt2>,<CRm>,<opc2>
984 Coproc = (OpCode32 >> 8) & 0xf;
985 Opc1 = (OpCode32 >> 20) & 0xf;
986 CRn = (OpCode32 >> 16) & 0xf;
987 CRm = OpCode32 & 0xf;
988 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " p%d,#%d,%a,%a,c%d", Coproc, Opc1, gReg[Rt], gReg[Rt2], CRm);
989 return;
990
991 case THUMB2_2REGS:
992 // <Rd>, <Rm>
993 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd], gReg[Rm]);
994 return;
995
996 case THUMB2_4REGS:
997 // <Rd>, <Rn>, <Rm>, <Ra>
998 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a, %a", gReg[Rd], gReg[Rn], gReg[Rm], gReg[Rt]);
999 return;
1000
1001 case THUMB2_MRS:
1002 // MRS <Rd>, CPSR
1003 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, CPSR", gReg[Rd]);
1004 return;
1005
1006 case THUMB2_MSR:
1007 // MRS CPSR_<fields>, <Rd>
1008 Target = (OpCode32 >> 10) & 3;
1009 AsciiSPrint (&Buf[Offset], Size - Offset, " CPSR_%a%a, %a", (Target & 2) == 0 ? "":"f", (Target & 1) == 0 ? "":"s", gReg[Rd]);
1010 return;
1011
1012 case THUMB2_NO_ARGS:
1013 default:
1014 break;
1015 }
1016 }
1017 }
1018
1019 AsciiSPrint (Buf, Size, "0x%08x", OpCode32);
1020 }
1021
1022
1023
1024 VOID
1025 DisassembleArmInstruction (
1026 IN UINT32 **OpCodePtr,
1027 OUT CHAR8 *Buf,
1028 OUT UINTN Size,
1029 IN BOOLEAN Extended
1030 );
1031
1032
1033 /**
1034 Place a disassembly of **OpCodePtr into buffer, and update OpCodePtr to
1035 point to next instruction.
1036
1037 We cheat and only decode instructions that access
1038 memory. If the instruction is not found we dump the instruction in hex.
1039
1040 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
1041 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream
1042 @param Extended TRUE dump hex for instruction too.
1043 @param ItBlock Size of IT Block
1044 @param Buf Buffer to sprintf disassembly into.
1045 @param Size Size of Buf in bytes.
1046
1047 **/
1048 VOID
1049 DisassembleInstruction (
1050 IN UINT8 **OpCodePtr,
1051 IN BOOLEAN Thumb,
1052 IN BOOLEAN Extended,
1053 IN OUT UINT32 *ItBlock,
1054 OUT CHAR8 *Buf,
1055 OUT UINTN Size
1056 )
1057 {
1058 if (Thumb) {
1059 DisassembleThumbInstruction ((UINT16 **)OpCodePtr, Buf, Size, ItBlock, Extended);
1060 } else {
1061 DisassembleArmInstruction ((UINT32 **)OpCodePtr, Buf, Size, Extended);
1062 }
1063 }
1064