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