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