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