1 /*
2 * \file trc_idec_arminst.cpp
3 * \brief OpenCSD :
4 *
5 * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
6 */
7
8
9 /*
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of the copyright holder nor the names of its contributors
21 * may be used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /*
37 Basic ARM/Thumb/A64 instruction decode, suitable for e.g. basic
38 block identification and trace decode.
39 */
40
41 #include "i_dec/trc_idec_arminst.h"
42
43
44 #include <stddef.h> /* for NULL */
45 #include <assert.h>
46
47
48 static ocsd_instr_subtype instr_sub_type = OCSD_S_INSTR_NONE;
49
get_instr_subtype()50 ocsd_instr_subtype get_instr_subtype()
51 {
52 return instr_sub_type;
53 }
54
clear_instr_subtype()55 void clear_instr_subtype()
56 {
57 instr_sub_type = OCSD_S_INSTR_NONE;
58 }
59
inst_ARM_is_direct_branch(uint32_t inst)60 int inst_ARM_is_direct_branch(uint32_t inst)
61 {
62 int is_direct_branch = 1;
63 if ((inst & 0xf0000000) == 0xf0000000) {
64 /* NV space */
65 if ((inst & 0xfe000000) == 0xfa000000){
66 /* BLX (imm) */
67 } else {
68 is_direct_branch = 0;
69 }
70 } else if ((inst & 0x0e000000) == 0x0a000000) {
71 /* B, BL */
72 } else {
73 is_direct_branch = 0;
74 }
75 return is_direct_branch;
76 }
77
78
inst_ARM_is_indirect_branch(uint32_t inst)79 int inst_ARM_is_indirect_branch(uint32_t inst)
80 {
81 int is_indirect_branch = 1;
82 if ((inst & 0xf0000000) == 0xf0000000) {
83 /* NV space */
84 if ((inst & 0xfe500000) == 0xf8100000) {
85 /* RFE */
86 } else {
87 is_indirect_branch = 0;
88 }
89 } else if ((inst & 0x0ff000d0) == 0x01200010) {
90 /* BLX (register), BX */
91 } else if ((inst & 0x0e108000) == 0x08108000) {
92 /* POP {...,pc} or LDMxx {...,pc} */
93 } else if ((inst & 0x0e50f000) == 0x0410f000) {
94 /* LDR PC,imm... inc. POP {PC} */
95 } else if ((inst & 0x0e50f010) == 0x0610f000) {
96 /* LDR PC,reg */
97 } else if ((inst & 0x0fe0f000) == 0x01a0f000) {
98 /* MOV PC,rx */
99 } else if ((inst & 0x0f900080) == 0x01000000) {
100 /* "Miscellaneous instructions" - in DP space */
101 is_indirect_branch = 0;
102 } else if ((inst & 0x0f9000f0) == 0x01800090) {
103 /* Some extended loads and stores */
104 is_indirect_branch = 0;
105 } else if ((inst & 0x0fb0f000) == 0x0320f000) {
106 /* MSR #imm */
107 is_indirect_branch = 0;
108 } else if ((inst & 0x0e00f000) == 0x0200f000) {
109 /* DP PC,imm shift */
110 if ((inst & 0x0f90f000) == 0x0310f000) {
111 /* TST/CMP */
112 is_indirect_branch = 0;
113 }
114 } else if ((inst & 0x0e00f000) == 0x0000f000) {
115 /* DP PC,reg */
116 } else {
117 is_indirect_branch = 0;
118 }
119 return is_indirect_branch;
120 }
121
122
inst_Thumb_is_direct_branch(uint32_t inst)123 int inst_Thumb_is_direct_branch(uint32_t inst)
124 {
125 int is_direct_branch = 1;
126 if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
127 /* B<c> (encoding T1) */
128 } else if ((inst & 0xf8000000) == 0xe0000000) {
129 /* B (encoding T2) */
130 } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
131 /* B (encoding T3) */
132 } else if ((inst & 0xf8009000) == 0xf0009000) {
133 /* B (encoding T4); BL (encoding T1) */
134 } else if ((inst & 0xf800d001) == 0xf000c000) {
135 /* BLX (imm) (encoding T2) */
136 } else if ((inst & 0xf5000000) == 0xb1000000) {
137 /* CB(NZ) */
138 } else {
139 is_direct_branch = 0;
140 }
141 return is_direct_branch;
142 }
143
144
inst_Thumb_is_indirect_branch(uint32_t inst)145 int inst_Thumb_is_indirect_branch(uint32_t inst)
146 {
147 /* See e.g. PFT Table 2-3 and Table 2-5 */
148 int is_branch = 1;
149 if ((inst & 0xff000000) == 0x47000000) {
150 /* BX, BLX (reg) */
151 } else if ((inst & 0xff000000) == 0xbd000000) {
152 /* POP {pc} */
153 } else if ((inst & 0xfd870000) == 0x44870000) {
154 /* MOV PC,reg or ADD PC,reg */
155 } else if ((inst & 0xfff0ffe0) == 0xe8d0f000) {
156 /* TBB/TBH */
157 } else if ((inst & 0xffd00000) == 0xe8100000) {
158 /* RFE (T1) */
159 } else if ((inst & 0xffd00000) == 0xe9900000) {
160 /* RFE (T2) */
161 } else if ((inst & 0xfff0d000) == 0xf3d08000) {
162 /* SUBS PC,LR,#imm inc.ERET */
163 } else if ((inst & 0xfff0f000) == 0xf8d0f000) {
164 /* LDR PC,imm (T3) */
165 } else if ((inst & 0xff7ff000) == 0xf85ff000) {
166 /* LDR PC,literal (T2) */
167 } else if ((inst & 0xfff0f800) == 0xf850f800) {
168 /* LDR PC,imm (T4) */
169 } else if ((inst & 0xfff0ffc0) == 0xf850f000) {
170 /* LDR PC,reg (T2) */
171 } else if ((inst & 0xfe508000) == 0xe8108000) {
172 /* LDM PC */
173 } else {
174 is_branch = 0;
175 }
176 return is_branch;
177 }
178
179
inst_A64_is_direct_branch(uint32_t inst)180 int inst_A64_is_direct_branch(uint32_t inst)
181 {
182 int is_direct_branch = 1;
183 if ((inst & 0x7c000000) == 0x34000000) {
184 /* CB, TB */
185 } else if ((inst & 0xff000010) == 0x54000000) {
186 /* B<cond> */
187 } else if ((inst & 0x7c000000) == 0x14000000) {
188 /* B, BL imm */
189 } else {
190 is_direct_branch = 0;
191 }
192 return is_direct_branch;
193 }
194
195
inst_A64_is_indirect_branch(uint32_t inst)196 int inst_A64_is_indirect_branch(uint32_t inst)
197 {
198 int is_indirect_branch = 1;
199 if ((inst & 0xffdffc1f) == 0xd61f0000) {
200 /* BR, BLR */
201 } else if ((inst & 0xfffffc1f) == 0xd65f0000) {
202 instr_sub_type = OCSD_S_INSTR_V8_RET;
203 /* RET */
204 } else if ((inst & 0xffffffff) == 0xd69f03e0) {
205 /* ERET */
206 instr_sub_type = OCSD_S_INSTR_V8_ERET;
207 } else {
208 is_indirect_branch = 0;
209 }
210 return is_indirect_branch;
211 }
212
213
inst_ARM_branch_destination(uint32_t addr,uint32_t inst,uint32_t * pnpc)214 int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
215 {
216 uint32_t npc;
217 int is_direct_branch = 1;
218 if ((inst & 0x0e000000) == 0x0a000000) {
219 /*
220 B: cccc:1010:imm24
221 BL: cccc:1011:imm24
222 BLX: 1111:101H:imm24
223 */
224 npc = addr + 8 + ((int32_t)((inst & 0xffffff) << 8) >> 6);
225 if ((inst & 0xf0000000) == 0xf0000000) {
226 npc |= 1; /* indicate ISA is now Thumb */
227 npc |= ((inst >> 23) & 2); /* apply the H bit */
228 }
229 } else {
230 is_direct_branch = 0;
231 }
232 if (is_direct_branch && pnpc != NULL) {
233 *pnpc = npc;
234 }
235 return is_direct_branch;
236 }
237
238
inst_Thumb_branch_destination(uint32_t addr,uint32_t inst,uint32_t * pnpc)239 int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
240 {
241 uint32_t npc;
242 int is_direct_branch = 1;
243 if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
244 /* B<c> (encoding T1) */
245 npc = addr + 4 + ((int32_t)((inst & 0x00ff0000) << 8) >> 23);
246 npc |= 1;
247 } else if ((inst & 0xf8000000) == 0xe0000000) {
248 /* B (encoding T2) */
249 npc = addr + 4 + ((int32_t)((inst & 0x07ff0000) << 5) >> 20);
250 npc |= 1;
251 } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
252 /* B (encoding T3) */
253 npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
254 ((inst & 0x0800) << 19) |
255 ((inst & 0x2000) << 16) |
256 ((inst & 0x003f0000) << 7) |
257 ((inst & 0x000007ff) << 12)) >> 11);
258 npc |= 1;
259 } else if ((inst & 0xf8009000) == 0xf0009000) {
260 /* B (encoding T4); BL (encoding T1) */
261 uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */
262 npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
263 (((inst^S) & 0x2000) << 17) |
264 (((inst^S) & 0x0800) << 18) |
265 ((inst & 0x03ff0000) << 3) |
266 ((inst & 0x000007ff) << 8)) >> 7);
267 npc |= 1;
268 } else if ((inst & 0xf800d001) == 0xf000c000) {
269 /* BLX (encoding T2) */
270 uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */
271 addr &= 0xfffffffc; /* Align(PC,4) */
272 npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
273 (((inst^S) & 0x2000) << 17) |
274 (((inst^S) & 0x0800) << 18) |
275 ((inst & 0x03ff0000) << 3) |
276 ((inst & 0x000007fe) << 8)) >> 7);
277 /* don't set the Thumb bit, as we're transferring to ARM */
278 } else if ((inst & 0xf5000000) == 0xb1000000) {
279 /* CB(NZ) */
280 /* Note that it's zero-extended - always a forward branch */
281 npc = addr + 4 + ((((inst & 0x02000000) << 6) |
282 ((inst & 0x00f80000) << 7)) >> 25);
283 npc |= 1;
284 } else {
285 is_direct_branch = 0;
286 }
287 if (is_direct_branch && pnpc != NULL) {
288 *pnpc = npc;
289 }
290 return is_direct_branch;
291 }
292
293
inst_A64_branch_destination(uint64_t addr,uint32_t inst,uint64_t * pnpc)294 int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc)
295 {
296 uint64_t npc;
297 int is_direct_branch = 1;
298 if ((inst & 0xff000010) == 0x54000000) {
299 /* B<cond> */
300 npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
301 } else if ((inst & 0x7c000000) == 0x14000000) {
302 /* B, BL imm */
303 npc = addr + ((int32_t)((inst & 0x03ffffff) << 6) >> 4);
304 } else if ((inst & 0x7e000000) == 0x34000000) {
305 /* CB */
306 npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
307 } else if ((inst & 0x7e000000) == 0x36000000) {
308 /* TB */
309 npc = addr + ((int32_t)((inst & 0x0007ffe0) << 13) >> 16);
310 } else {
311 is_direct_branch = 0;
312 }
313 if (is_direct_branch && pnpc != NULL) {
314 *pnpc = npc;
315 }
316 return is_direct_branch;
317 }
318
inst_ARM_is_branch(uint32_t inst)319 int inst_ARM_is_branch(uint32_t inst)
320 {
321 return inst_ARM_is_indirect_branch(inst) ||
322 inst_ARM_is_direct_branch(inst);
323 }
324
325
inst_Thumb_is_branch(uint32_t inst)326 int inst_Thumb_is_branch(uint32_t inst)
327 {
328 return inst_Thumb_is_indirect_branch(inst) ||
329 inst_Thumb_is_direct_branch(inst);
330 }
331
332
inst_A64_is_branch(uint32_t inst)333 int inst_A64_is_branch(uint32_t inst)
334 {
335 return inst_A64_is_indirect_branch(inst) ||
336 inst_A64_is_direct_branch(inst);
337 }
338
339
inst_ARM_is_branch_and_link(uint32_t inst)340 int inst_ARM_is_branch_and_link(uint32_t inst)
341 {
342 int is_branch = 1;
343 if ((inst & 0xf0000000) == 0xf0000000) {
344 if ((inst & 0xfe000000) == 0xfa000000){
345 instr_sub_type = OCSD_S_INSTR_BR_LINK;
346 /* BLX (imm) */
347 } else {
348 is_branch = 0;
349 }
350 } else if ((inst & 0x0f000000) == 0x0b000000) {
351 instr_sub_type = OCSD_S_INSTR_BR_LINK;
352 /* BL */
353 } else if ((inst & 0x0ff000f0) == 0x01200030) {
354 instr_sub_type = OCSD_S_INSTR_BR_LINK;
355 /* BLX (reg) */
356 } else {
357 is_branch = 0;
358 }
359 return is_branch;
360 }
361
362
inst_Thumb_is_branch_and_link(uint32_t inst)363 int inst_Thumb_is_branch_and_link(uint32_t inst)
364 {
365 int is_branch = 1;
366 if ((inst & 0xff800000) == 0x47800000) {
367 instr_sub_type = OCSD_S_INSTR_BR_LINK;
368 /* BLX (reg) */
369 } else if ((inst & 0xf800c000) == 0xf000c000) {
370 instr_sub_type = OCSD_S_INSTR_BR_LINK;
371 /* BL, BLX (imm) */
372 } else {
373 is_branch = 0;
374 }
375 return is_branch;
376 }
377
378
inst_A64_is_branch_and_link(uint32_t inst)379 int inst_A64_is_branch_and_link(uint32_t inst)
380 {
381 int is_branch = 1;
382 if ((inst & 0xfffffc1f) == 0xd63f0000) {
383 /* BLR */
384 instr_sub_type = OCSD_S_INSTR_BR_LINK;
385 } else if ((inst & 0xfc000000) == 0x94000000) {
386 /* BL */
387 instr_sub_type = OCSD_S_INSTR_BR_LINK;
388 } else {
389 is_branch = 0;
390 }
391 return is_branch;
392 }
393
394
inst_ARM_is_conditional(uint32_t inst)395 int inst_ARM_is_conditional(uint32_t inst)
396 {
397 return (inst & 0xe0000000) != 0xe0000000;
398 }
399
400
inst_Thumb_is_conditional(uint32_t inst)401 int inst_Thumb_is_conditional(uint32_t inst)
402 {
403 if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
404 /* B<c> (encoding T1) */
405 return 1;
406 } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
407 /* B<c> (encoding T3) */
408 return 1;
409 } else if ((inst & 0xf5000000) == 0xb1000000) {
410 /* CB(N)Z */
411 return 1;
412 }
413 return 0;
414 }
415
416
inst_Thumb_is_IT(uint32_t inst)417 unsigned int inst_Thumb_is_IT(uint32_t inst)
418 {
419 if ((inst & 0xff000000) == 0xbf000000 &&
420 (inst & 0x000f0000) != 0x00000000) {
421 if (inst & 0x00010000) {
422 return 4;
423 } else if (inst & 0x00020000) {
424 return 3;
425 } else if (inst & 0x00040000) {
426 return 2;
427 } else {
428 assert(inst & 0x00080000);
429 return 1;
430 }
431 } else {
432 return 0;
433 }
434 }
435
436
437 /*
438 Test whether an A64 instruction is conditional.
439
440 Instructions like CSEL, CSINV, CCMP are not classed as conditional.
441 They use the condition code but do one of two things with it,
442 neither a NOP. The "intruction categories" section of ETMv4
443 lists no (non branch) conditional instructions for A64.
444 */
inst_A64_is_conditional(uint32_t inst)445 int inst_A64_is_conditional(uint32_t inst)
446 {
447 if ((inst & 0x7c000000) == 0x34000000) {
448 /* CB, TB */
449 return 1;
450 } else if ((inst & 0xff000010) == 0x54000000) {
451 /* B.cond */
452 return 1;
453 }
454 return 0;
455 }
456
457
inst_ARM_barrier(uint32_t inst)458 arm_barrier_t inst_ARM_barrier(uint32_t inst)
459 {
460 if ((inst & 0xfff00000) == 0xf5700000) {
461 switch (inst & 0xf0) {
462 case 0x40:
463 return ARM_BARRIER_DSB;
464 case 0x50:
465 return ARM_BARRIER_DMB;
466 case 0x60:
467 return ARM_BARRIER_ISB;
468 default:
469 return ARM_BARRIER_NONE;
470 }
471 } else if ((inst & 0x0fff0f00) == 0x0e070f00) {
472 switch (inst & 0xff) {
473 case 0x9a:
474 return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */
475 case 0xba:
476 return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */
477 case 0x95:
478 return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */
479 default:
480 return ARM_BARRIER_NONE;
481 }
482 } else {
483 return ARM_BARRIER_NONE;
484 }
485 }
486
487
inst_Thumb_barrier(uint32_t inst)488 arm_barrier_t inst_Thumb_barrier(uint32_t inst)
489 {
490 if ((inst & 0xffffff00) == 0xf3bf8f00) {
491 switch (inst & 0xf0) {
492 case 0x40:
493 return ARM_BARRIER_DSB;
494 case 0x50:
495 return ARM_BARRIER_DMB;
496 case 0x60:
497 return ARM_BARRIER_ISB;
498 default:
499 return ARM_BARRIER_NONE;
500 }
501 } else if ((inst & 0xffff0f00) == 0xee070f00) {
502 /* Thumb2 CP15 barriers are unlikely... 1156T2 only? */
503 switch (inst & 0xff) {
504 case 0x9a:
505 return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */
506 case 0xba:
507 return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */
508 case 0x95:
509 return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */
510 default:
511 return ARM_BARRIER_NONE;
512 }
513 return ARM_BARRIER_NONE;
514 } else {
515 return ARM_BARRIER_NONE;
516 }
517 }
518
519
inst_A64_barrier(uint32_t inst)520 arm_barrier_t inst_A64_barrier(uint32_t inst)
521 {
522 if ((inst & 0xfffff09f) == 0xd503309f) {
523 switch (inst & 0x60) {
524 case 0x0:
525 return ARM_BARRIER_DSB;
526 case 0x20:
527 return ARM_BARRIER_DMB;
528 case 0x40:
529 return ARM_BARRIER_ISB;
530 default:
531 return ARM_BARRIER_NONE;
532 }
533 } else {
534 return ARM_BARRIER_NONE;
535 }
536 }
537
538
inst_ARM_is_UDF(uint32_t inst)539 int inst_ARM_is_UDF(uint32_t inst)
540 {
541 return (inst & 0xfff000f0) == 0xe7f000f0;
542 }
543
544
inst_Thumb_is_UDF(uint32_t inst)545 int inst_Thumb_is_UDF(uint32_t inst)
546 {
547 return (inst & 0xff000000) == 0xde000000 || /* T1 */
548 (inst & 0xfff0f000) == 0xf7f0a000; /* T2 */
549 }
550
551
inst_A64_is_UDF(uint32_t inst)552 int inst_A64_is_UDF(uint32_t inst)
553 {
554 /* No A64 encodings are formally allocated as permanently undefined,
555 but it is intended not to allocate any instructions in the 21-bit
556 regions at the bottom or top of the range. */
557 return (inst & 0xffe00000) == 0x00000000 ||
558 (inst & 0xffe00000) == 0xffe00000;
559 }
560
561 /* End of File trc_idec_arminst.cpp */
562