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