]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/ArmDisassemblerLib/ThumbDisassembler.c
Added Thumb2 loads and stores to Disassmebler
[mirror_edk2.git] / ArmPkg / Library / ArmDisassemblerLib / ThumbDisassembler.c
1 /** @file
2 Thumb Dissassembler. Still a work in progress.
3
4 Wrong output is a bug, so please fix it.
5 Hex output means there is not yet an entry or a decode bug.
6 gOpThumb[] are Thumb 16-bit, and gOpThumb2[] work on the 32-bit
7 16-bit stream of Thumb2 instruction. Then there are big case
8 statements to print everything out. If you are adding instructions
9 try to reuse existing case entries if possible.
10
11 Copyright (c) 2008-2010, Apple Inc. All rights reserved.
12
13 All rights reserved. This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
17
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20
21 **/
22
23 #include <Base.h>
24 #include <Library/BaseLib.h>
25 #include <Library/PrintLib.h>
26
27 extern CHAR8 *gCondition[];
28
29 extern CHAR8 *gReg[];
30
31 // Thumb address modes
32 #define LOAD_STORE_FORMAT1 1
33 #define LOAD_STORE_FORMAT2 2
34 #define LOAD_STORE_FORMAT3 3
35 #define LOAD_STORE_FORMAT4 4
36 #define LOAD_STORE_MULTIPLE_FORMAT1 5
37 #define PUSH_FORMAT 6
38 #define POP_FORMAT 106
39 #define IMMED_8 7
40 #define CONDITIONAL_BRANCH 8
41 #define UNCONDITIONAL_BRANCH 9
42 #define UNCONDITIONAL_BRANCH_SHORT 109
43 #define BRANCH_EXCHANGE 10
44 #define DATA_FORMAT1 11
45 #define DATA_FORMAT2 12
46 #define DATA_FORMAT3 13
47 #define DATA_FORMAT4 14
48 #define DATA_FORMAT5 15
49 #define DATA_FORMAT6_SP 16
50 #define DATA_FORMAT6_PC 116
51 #define DATA_FORMAT7 17
52 #define DATA_FORMAT8 19
53 #define CPS_FORMAT 20
54 #define ENDIAN_FORMAT 21
55 #define DATA_CBZ 22
56 #define ADR_FORMAT 23
57
58 // Thumb2 address modes
59 #define B_T3 200
60 #define B_T4 201
61 #define BL_T2 202
62 #define POP_T2 203
63 #define POP_T3 204
64 #define STM_FORMAT 205
65 #define LDM_REG_IMM12_SIGNED 206
66 #define LDM_REG_IMM12_LSL 207
67 #define LDM_REG_IMM8 208
68 #define LDM_REG_IMM12 209
69 #define LDM_REG_INDIRECT_LSL 210
70 #define LDM_REG_IMM8_SIGNED 211
71 #define LDRD_REG_IMM8 212
72 #define LDREXB 213
73 #define LDREXD 214
74 #define SRS_FORMAT 215
75 #define RFE_FORMAT 216
76 #define LDRD_REG_IMM8_SIGNED 217
77
78
79
80
81 typedef struct {
82 CHAR8 *Start;
83 UINT32 OpCode;
84 UINT32 Mask;
85 UINT32 AddressMode;
86 } THUMB_INSTRUCTIONS;
87
88 THUMB_INSTRUCTIONS gOpThumb[] = {
89 // Thumb 16-bit instrucitons
90 // Op Mask Format
91 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5 },
92 { "ADR", 0xa000, 0xf800, ADR_FORMAT }, // ADR <Rd>, <label>
93 { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2 },
94 { "ADD" , 0x3000, 0xf800, DATA_FORMAT3 },
95 { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1 },
96 { "ADD" , 0x4400, 0xff00, DATA_FORMAT8 }, // A8.6.9
97 { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC },
98 { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP },
99 { "ADD" , 0xb000, 0xff80, DATA_FORMAT7 },
100
101 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5 },
102
103 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4 },
104 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5 },
105
106 { "B" , 0xd000, 0xf000, CONDITIONAL_BRANCH },
107 { "B" , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT },
108 { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE },
109 { "BX" , 0x4700, 0xff87, BRANCH_EXCHANGE },
110
111 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5 },
112 { "BKPT", 0xdf00, 0xff00, IMMED_8 },
113 { "CBZ", 0xb100, 0xfd00, DATA_CBZ },
114 { "CBNZ", 0xb900, 0xfd00, DATA_CBZ },
115 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5 },
116
117 { "CMP" , 0x2800, 0xf800, DATA_FORMAT3 },
118 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5 },
119 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8 },
120
121 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT },
122 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
123 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5 },
124
125 { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
126 { "LDR" , 0x6800, 0xf800, LOAD_STORE_FORMAT1 },
127 { "LDR" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },
128 { "LDR" , 0x4800, 0xf800, LOAD_STORE_FORMAT3 },
129 { "LDR" , 0x9800, 0xf800, LOAD_STORE_FORMAT4 },
130 { "LDRB" , 0x7800, 0xf800, LOAD_STORE_FORMAT1 },
131 { "LDRB" , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2 },
132 { "LDRH" , 0x8800, 0xf800, LOAD_STORE_FORMAT1 },
133 { "LDRH" , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2 },
134 { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2 },
135 { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2 },
136
137 { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5 }, // LSL with imm5 == 0 is a MOVS, so this must go before LSL
138 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4 },
139 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5 },
140 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4 },
141 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5 },
142
143 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3 },
144 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3 },
145 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
146
147 { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5 },
148 { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5 },
149 { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5 },
150 { "ORR" , 0x4180, 0xffc0, DATA_FORMAT5 },
151 { "POP" , 0xbc00, 0xfe00, POP_FORMAT },
152 { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT },
153
154 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5 },
155 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5 },
156 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5 },
157
158 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5 },
159 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5 },
160 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT },
161
162 { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },
163 { "STR" , 0x6000, 0xf800, LOAD_STORE_FORMAT1 },
164 { "STR" , 0x5000, 0xfe00, LOAD_STORE_FORMAT2 },
165 { "STR" , 0x4000, 0xf800, LOAD_STORE_FORMAT3 },
166 { "STR" , 0x9000, 0xf800, LOAD_STORE_FORMAT4 },
167 { "STRB" , 0x7000, 0xf800, LOAD_STORE_FORMAT1 },
168 { "STRB" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },
169 { "STRH" , 0x8000, 0xf800, LOAD_STORE_FORMAT1 },
170 { "STRH" , 0x5200, 0xfe00, LOAD_STORE_FORMAT2 },
171
172 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2 },
173 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3 },
174 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1 },
175 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7 },
176
177 { "SWI" , 0xdf00, 0xff00, IMMED_8 },
178 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5 },
179 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5 },
180 { "TST" , 0x4200, 0xffc0, DATA_FORMAT5 },
181 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5 },
182 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5 }
183
184 };
185
186 THUMB_INSTRUCTIONS gOpThumb2[] = {
187 //Instruct OpCode OpCode Mask Addressig Mode
188 { "B", 0xf0008000, 0xf800d000, B_T3 }, // B<c> <label>
189 { "B", 0xf0009000, 0xf800d000, B_T4 }, // B<c> <label>
190 { "BL", 0xf000d000, 0xf800d000, B_T4 }, // BL<c> <label>
191 { "BLX", 0xf000c000, 0xf800d000, BL_T2 }, // BLX<c> <label>
192
193 { "POP", 0xe8bd0000, 0xffff2000, POP_T2 }, // POP <registers>
194 { "POP", 0xf85d0b04, 0xffff0fff, POP_T3 }, // POP <register>
195 { "PUSH", 0xe8ad0000, 0xffffa000, POP_T2 }, // PUSH <registers>
196 { "PUSH", 0xf84d0d04, 0xffff0fff, POP_T3 }, // PUSH <register>
197 { "STM" , 0xe8800000, 0xffd0a000, STM_FORMAT }, // STM <Rn>{!},<registers>
198 { "STMDB", 0xe9800000, 0xffd0a000, STM_FORMAT }, // STMDB <Rn>{!},<registers>
199 { "LDM" , 0xe8900000, 0xffd02000, STM_FORMAT }, // LDM <Rn>{!},<registers>
200 { "LDMDB", 0xe9100000, 0xffd02000, STM_FORMAT }, // LDMDB <Rn>{!},<registers>
201
202 { "LDR", 0xf8d00000, 0xfff00000, LDM_REG_IMM12 }, // LDR <rt>, [<rn>, {, #<imm12>]}
203 { "LDRB", 0xf8900000, 0xfff00000, LDM_REG_IMM12 }, // LDRB <rt>, [<rn>, {, #<imm12>]}
204 { "LDRH", 0xf8b00000, 0xfff00000, LDM_REG_IMM12 }, // LDRH <rt>, [<rn>, {, #<imm12>]}
205 { "LDRSB", 0xf9900000, 0xfff00000, LDM_REG_IMM12 }, // LDRSB <rt>, [<rn>, {, #<imm12>]}
206 { "LDRSH", 0xf9b00000, 0xfff00000, LDM_REG_IMM12 }, // LDRSH <rt>, [<rn>, {, #<imm12>]}
207
208 { "LDR", 0xf85f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDR <Rt>, <label>
209 { "LDRB", 0xf81f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRB <Rt>, <label>
210 { "LDRH", 0xf83f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRH <Rt>, <label>
211 { "LDRSB", 0xf91f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRSB <Rt>, <label>
212 { "LDRSH", 0xf93f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRSB <Rt>, <label>
213
214 { "LDR", 0xf8500000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
215 { "LDRB", 0xf8100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
216 { "LDRH", 0xf8300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
217 { "LDRSB", 0xf9100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
218 { "LDRSH", 0xf9300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
219
220 { "LDR", 0xf8500800, 0xfff00800, LDM_REG_IMM8 }, // LDR <rt>, [<rn>, {, #<imm8>]}
221 { "LDRBT", 0xf8100e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRBT <rt>, [<rn>, {, #<imm8>]}
222 { "LDRHT", 0xf8300e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRHT <rt>, [<rn>, {, #<imm8>]}
223 { "LDRSB", 0xf9900800, 0xfff00800, LDM_REG_IMM8 }, // LDRHT <rt>, [<rn>, {, #<imm8>]} {!} form?
224 { "LDRSBT",0xf9100e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRHBT <rt>, [<rn>, {, #<imm8>]} {!} form?
225 { "LDRSH" ,0xf9300800, 0xfff00800, LDM_REG_IMM8 }, // LDRSH <rt>, [<rn>, {, #<imm8>]}
226 { "LDRSHT",0xf9300e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRSHT <rt>, [<rn>, {, #<imm8>]}
227 { "LDRT", 0xf8500e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRT <rt>, [<rn>, {, #<imm8>]}
228
229 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
230 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8 }, // LDRD <rt>, <rt2>, <label>
231
232 { "LDREX", 0xe8500f00, 0xfff00f00, LDM_REG_IMM8 }, // LDREX <Rt>, [Rn, {#imm8}]]
233 { "LDREXB", 0xe8d00f4f, 0xfff00fff, LDREXB }, // LDREXB <Rt>, [<Rn>]
234 { "LDREXH", 0xe8d00f5f, 0xfff00fff, LDREXB }, // LDREXH <Rt>, [<Rn>]
235
236 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // LDREXD <Rt>, <Rt2>, [<Rn>]
237
238 { "STR", 0xf8c00000, 0xfff00000, LDM_REG_IMM12 }, // STR <rt>, [<rn>, {, #<imm12>]}
239 { "STRB", 0xf8800000, 0xfff00000, LDM_REG_IMM12 }, // STRB <rt>, [<rn>, {, #<imm12>]}
240 { "STRH", 0xf8a00000, 0xfff00000, LDM_REG_IMM12 }, // STRH <rt>, [<rn>, {, #<imm12>]}
241
242 { "STR", 0xf8400000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
243 { "STRB", 0xf8000000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
244 { "STRH", 0xf8200000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
245
246 { "STR", 0xf8400800, 0xfff00800, LDM_REG_IMM8 }, // STR <rt>, [<rn>, {, #<imm8>]}
247 { "STRH", 0xf8200800, 0xfff00800, LDM_REG_IMM8 }, // STRH <rt>, [<rn>, {, #<imm8>]}
248 { "STRBT", 0xf8000e00, 0xfff00f00, LDM_REG_IMM8 }, // STRBT <rt>, [<rn>, {, #<imm8>]}
249 { "STRHT", 0xf8200e00, 0xfff00f00, LDM_REG_IMM8 }, // STRHT <rt>, [<rn>, {, #<imm8>]}
250 { "STRT", 0xf8400e00, 0xfff00f00, LDM_REG_IMM8 }, // STRT <rt>, [<rn>, {, #<imm8>]}
251
252 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
253
254 { "STREX", 0xe8400f00, 0xfff00f00, LDM_REG_IMM8 }, // STREX <Rt>, [Rn, {#imm8}]]
255 { "STREXB", 0xe8c00f4f, 0xfff00fff, LDREXB }, // STREXB <Rd>, <Rt>, [<Rn>]
256 { "STREXH", 0xe8c00f5f, 0xfff00fff, LDREXB }, // STREXH <Rd>, <Rt>, [<Rn>]
257
258 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
259
260 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT }, // SRSDB<c> SP{!},#<mode>
261 { "SRS" , 0xe98dc000, 0xffdffff0, SRS_FORMAT }, // SRS{IA}<c> SP{!},#<mode>
262 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT }, // RFEDB<c> <Rn>{!}
263 { "RFE" , 0xe990c000, 0xffd0ffff, RFE_FORMAT } // RFE{IA}<c> <Rn>{!}
264 };
265
266 CHAR8 mThumbMregListStr[4*15 + 1];
267
268 CHAR8 *
269 ThumbMRegList (
270 UINT32 RegBitMask
271 )
272 {
273 UINTN Index, Start, End;
274 CHAR8 *Str;
275 BOOLEAN First;
276
277 Str = mThumbMregListStr;
278 *Str = '\0';
279 AsciiStrCat (Str, "{");
280 // R0 - R7, PC
281 for (Index = 0, First = TRUE; Index <= 15; Index++) {
282 if ((RegBitMask & (1 << Index)) != 0) {
283 Start = End = Index;
284 for (Index++; ((RegBitMask & (1 << Index)) != 0) && (Index <= 9); Index++) {
285 End = Index;
286 }
287
288 if (!First) {
289 AsciiStrCat (Str, ",");
290 } else {
291 First = FALSE;
292 }
293
294 if (Start == End) {
295 AsciiStrCat (Str, gReg[Start]);
296 } else {
297 AsciiStrCat (Str, gReg[Start]);
298 AsciiStrCat (Str, "-");
299 AsciiStrCat (Str, gReg[End]);
300 }
301 }
302 }
303 if (First) {
304 AsciiStrCat (Str, "ERROR");
305 }
306 AsciiStrCat (Str, "}");
307
308 // BugBug: Make caller pass in buffer it is cleaner
309 return mThumbMregListStr;
310 }
311
312 UINT32
313 SignExtend32 (
314 IN UINT32 Data,
315 IN UINT32 TopBit
316 )
317 {
318 if (((Data & TopBit) == 0) || (TopBit == BIT31)) {
319 return Data;
320 }
321
322 do {
323 TopBit <<= 1;
324 Data |= TopBit;
325 } while ((TopBit & BIT31) != BIT31);
326
327 return Data;
328 }
329
330 /**
331 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
332 point to next instructin.
333
334 We cheat and only decode instructions that access
335 memory. If the instruction is not found we dump the instruction in hex.
336
337 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
338 @param Buf Buffer to sprintf disassembly into.
339 @param Size Size of Buf in bytes.
340 @param Extended TRUE dump hex for instruction too.
341
342 **/
343 VOID
344 DisassembleThumbInstruction (
345 IN UINT16 **OpCodePtrPtr,
346 OUT CHAR8 *Buf,
347 OUT UINTN Size,
348 IN BOOLEAN Extended
349 )
350 {
351 UINT16 *OpCodePtr;
352 UINT16 OpCode;
353 UINT32 OpCode32;
354 UINT32 Index;
355 UINT32 Offset;
356 UINT16 Rd, Rn, Rm, Rt, Rt2;
357 BOOLEAN H1, H2, imod;
358 UINT32 PC, Target;
359 CHAR8 *Cond;
360 BOOLEAN S, J1, J2, P, U, W;
361
362 OpCodePtr = *OpCodePtrPtr;
363 OpCode = **OpCodePtrPtr;
364
365 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
366 OpCode32 = (((UINT32)OpCode) << 16) | *(OpCodePtr + 1);
367
368 // These register names match branch form, but not others
369 Rd = OpCode & 0x7;
370 Rn = (OpCode >> 3) & 0x7;
371 Rm = (OpCode >> 6) & 0x7;
372 H1 = (OpCode & BIT7) != 0;
373 H2 = (OpCode & BIT6) != 0;
374 imod = (OpCode & BIT4) != 0;
375 PC = (UINT32)(UINTN)OpCodePtr;
376
377 // Increment by the minimum instruction size, Thumb2 could be bigger
378 *OpCodePtrPtr += 1;
379
380 for (Index = 0; Index < sizeof (gOpThumb)/sizeof (THUMB_INSTRUCTIONS); Index++) {
381 if ((OpCode & gOpThumb[Index].Mask) == gOpThumb[Index].OpCode) {
382 if (Extended) {
383 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode, gOpThumb[Index].Start);
384 } else {
385 Offset = AsciiSPrint (Buf, Size, "%-6a", gOpThumb[Index].Start);
386 }
387 switch (gOpThumb[Index].AddressMode) {
388 case LOAD_STORE_FORMAT1:
389 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
390 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 4) & 0x7c);
391 return;
392 case LOAD_STORE_FORMAT2:
393 // A6.5.1 <Rd>, [<Rn>, <Rm>]
394 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d, r%d]", Rd, Rn, Rm);
395 return;
396 case LOAD_STORE_FORMAT3:
397 // A6.5.1 <Rd>, [PC, #<8_bit_offset>]
398 Target = (OpCode & 0xff) << 2;
399 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [pc, #0x%x] ;0x%08x", (OpCode >> 8) & 7, Target, PC + 2 + Target);
400 return;
401 case LOAD_STORE_FORMAT4:
402 // Rt, [SP, #imm8]
403 Target = (OpCode & 0xff) << 2;
404 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [sp, #0x%x]", (OpCode >> 8) & 7, Target, PC + 2 + Target);
405 return;
406
407 case LOAD_STORE_MULTIPLE_FORMAT1:
408 // <Rn>!, {r0-r7}
409 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (OpCode & 0xff));
410 return;
411
412 case POP_FORMAT:
413 // POP {r0-r7,pc}
414 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT15 : 0)));
415 return;
416
417 case PUSH_FORMAT:
418 // PUSH {r0-r7,lr}
419 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT14 : 0)));
420 return;
421
422
423 case IMMED_8:
424 // A6.7 <immed_8>
425 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%x", OpCode & 0xff);
426 return;
427
428 case CONDITIONAL_BRANCH:
429 // A6.3.1 B<cond> <target_address>
430 // Patch in the condition code. A little hack but based on "%-6a"
431 Cond = gCondition[(OpCode >> 8) & 0xf];
432 Buf[Offset-5] = *Cond++;
433 Buf[Offset-4] = *Cond;
434 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0xff) << 1, BIT8));
435 return;
436 case UNCONDITIONAL_BRANCH_SHORT:
437 // A6.3.2 B <target_address>
438 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0x3ff) << 1, BIT11));
439 return;
440
441 case BRANCH_EXCHANGE:
442 // A6.3.3 BX|BLX <Rm>
443 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[Rn | (H2 ? 8:0)]);
444 return;
445
446 case DATA_FORMAT1:
447 // A6.4.3 <Rd>, <Rn>, <Rm>
448 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, r%d", Rd, Rn, Rm);
449 return;
450 case DATA_FORMAT2:
451 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
452 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rd, Rn, Rm);
453 return;
454 case DATA_FORMAT3:
455 // A6.4.3 <Rd>|<Rn>, #imm8
456 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, #0x%x", (OpCode >> 8) & 7, OpCode & 0xff);
457 return;
458 case DATA_FORMAT4:
459 // A6.4.3 <Rd>|<Rm>, #immed_5
460 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rn, Rd, (OpCode >> 6) & 0x1f);
461 return;
462 case DATA_FORMAT5:
463 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
464 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d", Rd, Rn);
465 return;
466 case DATA_FORMAT6_SP:
467 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
468 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, sp, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2);
469 return;
470 case DATA_FORMAT6_PC:
471 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
472 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, pc, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2);
473 return;
474 case DATA_FORMAT7:
475 // A6.4.3 SP, SP, #<7_Bit_immed>
476 AsciiSPrint (&Buf[Offset], Size - Offset, " sp, sp, 0x%x", (OpCode & 0x7f)*4);
477 return;
478 case DATA_FORMAT8:
479 // A6.4.3 <Rd>|<Rn>, <Rm>
480 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd | (H1 ? 8:0)], gReg[Rn | (H2 ? 8:0)]);
481 return;
482
483 case CPS_FORMAT:
484 // A7.1.24
485 AsciiSPrint (&Buf[Offset], Size - Offset, "%a %a%a%a", imod ? "ID":"IE", ((OpCode & BIT2) == 0) ? "":"a", ((OpCode & BIT1) == 0) ? "":"i", ((OpCode & BIT0) == 0) ? "":"f");
486 return;
487
488 case ENDIAN_FORMAT:
489 // A7.1.24
490 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", (OpCode & BIT3) == 0 ? "LE":"BE");
491 return;
492
493 case DATA_CBZ:
494 // CB{N}Z <Rn>, <Lable>
495 Target = ((OpCode >> 2) & 0x3e) | (((OpCode & BIT9) == BIT9) ? BIT6 : 0);
496 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[Rd], PC + 4 + Target);
497 return;
498
499 case ADR_FORMAT:
500 // ADR <Rd>, <Label>
501 Target = (OpCode & 0xff) << 2;
502 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[(OpCode >> 8) & 7], PC + 4 + Target);
503 return;
504 }
505 }
506 }
507
508
509 // Thumb2 are 32-bit instructions
510 *OpCodePtrPtr += 1;
511 Rt = (OpCode32 >> 12) & 0xf;
512 Rt2 = (OpCode32 >> 8) & 0xf;
513 Rm = (OpCode32 & 0xf);
514 Rn = (OpCode32 >> 16) & 0xf;
515 for (Index = 0; Index < sizeof (gOpThumb2)/sizeof (THUMB_INSTRUCTIONS); Index++) {
516 if ((OpCode32 & gOpThumb2[Index].Mask) == gOpThumb2[Index].OpCode) {
517 if (Extended) {
518 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode32, gOpThumb2[Index].Start);
519 } else {
520 Offset = AsciiSPrint (Buf, Size, " %-6a", gOpThumb2[Index].Start);
521 }
522 switch (gOpThumb2[Index].AddressMode) {
523 case B_T3:
524 Cond = gCondition[(OpCode32 >> 22) & 0xf];
525 Buf[Offset-5] = *Cond++;
526 Buf[Offset-4] = *Cond;
527 // S:J2:J1:imm6:imm11:0
528 Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3f000);
529 Target |= ((OpCode32 & BIT11) == BIT11)? BIT19 : 0; // J2
530 Target |= ((OpCode32 & BIT13) == BIT13)? BIT18 : 0; // J1
531 Target |= ((OpCode32 & BIT26) == BIT26)? BIT20 : 0; // S
532 Target = SignExtend32 (Target, BIT20);
533 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target);
534 return;
535 case B_T4:
536 // S:I1:I2:imm10:imm11:0
537 Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3ff000);
538 S = (OpCode32 & BIT26) == BIT26;
539 J1 = (OpCode32 & BIT13) == BIT13;
540 J2 = (OpCode32 & BIT11) == BIT11;
541 Target |= (!(J2 ^ S) ? BIT22 : 0); // I2
542 Target |= (!(J1 ^ S) ? BIT23 : 0); // I1
543 Target |= (S ? BIT24 : 0); // S
544 Target = SignExtend32 (Target, BIT24);
545 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target);
546 return;
547
548 case BL_T2:
549 // S:I1:I2:imm10:imm11:00
550 Target = ((OpCode32 << 2) & 0x1ffc) + ((OpCode32 >> 3) & 0x7fe000);
551 S = (OpCode32 & BIT26) == BIT26;
552 J1 = (OpCode32 & BIT13) == BIT13;
553 J2 = (OpCode32 & BIT11) == BIT11;
554 Target |= (!(J2 ^ S) ? BIT23 : 0); // I2
555 Target |= (!(J1 ^ S) ? BIT24 : 0); // I1
556 Target |= (S ? BIT25 : 0); // S
557 Target = SignExtend32 (Target, BIT25);
558 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target);
559 return;
560
561 case POP_T2:
562 // <reglist> some must be zero, handled in table
563 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList (OpCode32 & 0xffff));
564 return;
565
566 case POP_T3:
567 // <register>
568 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[(OpCode32 >> 12) & 0xf]);
569 return;
570
571 case STM_FORMAT:
572 // <Rn>{!}, <registers>
573 W = (OpCode32 & BIT21) == BIT21;
574 AsciiSPrint (&Buf[Offset], Size - Offset, " %a %a", gReg[(OpCode32 >> 16) & 0xf], W ? "!":"", ThumbMRegList (OpCode32 & 0xffff));
575 return;
576
577 case LDM_REG_IMM12_SIGNED:
578 // <rt>, <label>
579 Target = OpCode32 & 0xfff;
580 if ((OpCode32 & BIT23) == 0) {
581 // U == 0 means subtrack, U == 1 means add
582 Target = -Target;
583 }
584 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[(OpCode32 >> 12) & 0xf], PC + 4 + Target);
585 return;
586
587 case LDM_REG_INDIRECT_LSL:
588 // <rt>, [<rn>, <rm> {, LSL #<imm2>]}
589 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a, %a", gReg[Rt], gReg[Rn], gReg[Rm]);
590 if (((OpCode32 >> 4) && 3) == 0) {
591 AsciiSPrint (&Buf[Offset], Size - Offset, "]");
592 } else {
593 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL #%d]", (OpCode32 >> 4) && 3);
594 }
595 return;
596
597 case LDM_REG_IMM12:
598 // <rt>, [<rn>, {, #<imm12>]}
599 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);
600 if ((OpCode32 && 0xfff) == 0) {
601 AsciiSPrint (&Buf[Offset], Size - Offset, "]");
602 } else {
603 AsciiSPrint (&Buf[Offset], Size - Offset, ", #0x%x]", OpCode32 & 0xfff);
604 }
605 return;
606
607 case LDM_REG_IMM8:
608 // <rt>, [<rn>, {, #<imm8>}]{!}
609 W = (OpCode32 & BIT8) == BIT8;
610 U = (OpCode32 & BIT9) == BIT9;
611 P = (OpCode32 & BIT10) == BIT10;
612 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);
613 if (P) {
614 if ((OpCode32 && 0xff) == 0) {
615 AsciiSPrint (&Buf[Offset], Size - Offset, "]%a", W?"!":"");
616 } else {
617 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", OpCode32 & 0xff, U?"":"-" ,W?"!":"");
618 }
619 } else {
620 AsciiSPrint (&Buf[Offset], Size - Offset, "], #%a0x%x]%a", OpCode32 & 0xff, U?"":"-");
621 }
622 return;
623
624 case LDRD_REG_IMM8_SIGNED:
625 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
626 P = (OpCode32 & BIT24) == BIT24; // index = P
627 U = (OpCode32 & BIT23) == BIT23;
628 W = (OpCode32 & BIT21) == BIT21;
629 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, [%a", gReg[Rt], gReg[Rt2], gReg[Rn]);
630 if (P) {
631 if ((OpCode32 && 0xff) == 0) {
632 AsciiSPrint (&Buf[Offset], Size - Offset, "]");
633 } else {
634 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-", (OpCode32 & 0xff) << 2, W?"!":"");
635 }
636 } else {
637 if ((OpCode32 && 0xff) != 0) {
638 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x", U?"":"-", (OpCode32 & 0xff) << 2);
639 }
640 }
641 return;
642
643 case LDRD_REG_IMM8:
644 // LDRD <rt>, <rt2>, <label>
645 Target = (OpCode32 & 0xff) << 2;
646 if ((OpCode32 & BIT23) == 0) {
647 // U == 0 means subtrack, U == 1 means add
648 Target = -Target;
649 }
650 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rt], gReg[Rt2], PC + 4 + Target);
651 return;
652
653 case LDREXB:
654 // LDREXB <Rt>, [Rn]
655 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a]", gReg[Rt], gReg[Rn]);
656 return;
657
658 case LDREXD:
659 // LDREXD <Rt>, <Rt2>, [<Rn>]
660 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, [%a]", gReg[Rt], gReg[Rt2], gReg[Rn]);
661 return;
662
663 case SRS_FORMAT:
664 // SP{!}, #<mode>
665 W = (OpCode32 & BIT21) == BIT21;
666 AsciiSPrint (&Buf[Offset], Size - Offset, " SP%a, #0x%x", W?"!":"", OpCode32 & 0x1f);
667 return;
668
669 case RFE_FORMAT:
670 // <Rn>{!}
671 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, #0x%x", gReg[Rn], W?"!":"");
672 return;
673
674 }
675 }
676 }
677
678 AsciiSPrint (Buf, Size, "0x%08x", OpCode32);
679 }
680
681
682
683 VOID
684 DisassembleArmInstruction (
685 IN UINT32 **OpCodePtr,
686 OUT CHAR8 *Buf,
687 OUT UINTN Size,
688 IN BOOLEAN Extended
689 );
690
691
692 /**
693 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
694 point to next instructin.
695
696 We cheat and only decode instructions that access
697 memory. If the instruction is not found we dump the instruction in hex.
698
699 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
700 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream
701 @param Extended TRUE dump hex for instruction too.
702 @param Buf Buffer to sprintf disassembly into.
703 @param Size Size of Buf in bytes.
704
705 **/
706 VOID
707 DisassembleInstruction (
708 IN UINT8 **OpCodePtr,
709 IN BOOLEAN Thumb,
710 IN BOOLEAN Extended,
711 OUT CHAR8 *Buf,
712 OUT UINTN Size
713 )
714 {
715 if (Thumb) {
716 DisassembleThumbInstruction ((UINT16 **)OpCodePtr, Buf, Size, Extended);
717 } else {
718 DisassembleArmInstruction ((UINT32 **)OpCodePtr, Buf, Size, Extended);
719 }
720 }
721