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