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 
50 ocsd_instr_subtype get_instr_subtype()
51 {
52     return instr_sub_type;
53 }
54 
55 void clear_instr_subtype()
56 {
57     instr_sub_type = OCSD_S_INSTR_NONE;
58 }
59 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
395 int inst_ARM_is_conditional(uint32_t inst)
396 {
397     return (inst & 0xe0000000) != 0xe0000000;
398 }
399 
400 
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 
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 */
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 
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 
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 
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 
539 int inst_ARM_is_UDF(uint32_t inst)
540 {
541     return (inst & 0xfff000f0) == 0xe7f000f0;
542 }
543 
544 
545 int inst_Thumb_is_UDF(uint32_t inst)
546 {
547     return (inst & 0xff000000) == 0xde000000 ||   /* T1 */
548            (inst & 0xfff0f000) == 0xf7f0a000;     /* T2 */
549 }
550 
551 
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