1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * A small micro-assembler. It is intentionally kept simple, does only 7 * support a subset of instructions, and does not try to hide pipeline 8 * effects like branch delay slots. 9 * 10 * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer 11 * Copyright (C) 2005, 2007 Maciej W. Rozycki 12 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) 13 * Copyright (C) 2012, 2013 MIPS Technologies, Inc. All rights reserved. 14 */ 15 16 enum fields { 17 RS = 0x001, 18 RT = 0x002, 19 RD = 0x004, 20 RE = 0x008, 21 SIMM = 0x010, 22 UIMM = 0x020, 23 BIMM = 0x040, 24 JIMM = 0x080, 25 FUNC = 0x100, 26 SET = 0x200, 27 SCIMM = 0x400 28 }; 29 30 #define OP_MASK 0x3f 31 #define OP_SH 26 32 #define RD_MASK 0x1f 33 #define RD_SH 11 34 #define RE_MASK 0x1f 35 #define RE_SH 6 36 #define IMM_MASK 0xffff 37 #define IMM_SH 0 38 #define JIMM_MASK 0x3ffffff 39 #define JIMM_SH 0 40 #define FUNC_MASK 0x3f 41 #define FUNC_SH 0 42 #define SET_MASK 0x7 43 #define SET_SH 0 44 45 enum opcode { 46 insn_invalid, 47 insn_addiu, insn_addu, insn_and, insn_andi, insn_bbit0, insn_bbit1, 48 insn_beq, insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl, 49 insn_bne, insn_cache, insn_daddiu, insn_daddu, insn_dins, insn_dinsm, 50 insn_divu, insn_dmfc0, insn_dmtc0, insn_drotr, insn_drotr32, insn_dsll, 51 insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32, insn_dsubu, insn_eret, 52 insn_ext, insn_ins, insn_j, insn_jal, insn_jalr, insn_jr, insn_ld, 53 insn_ldx, insn_lh, insn_ll, insn_lld, insn_lui, insn_lw, insn_lwx, 54 insn_mfc0, insn_mfhi, insn_mtc0, insn_mul, insn_or, insn_ori, insn_pref, 55 insn_rfe, insn_rotr, insn_sc, insn_scd, insn_sd, insn_sll, insn_sllv, 56 insn_sltiu, insn_sltu, insn_sra, insn_srl, insn_srlv, insn_subu, 57 insn_sw, insn_sync, insn_syscall, insn_tlbp, insn_tlbr, insn_tlbwi, 58 insn_tlbwr, insn_wait, insn_wsbh, insn_xor, insn_xori, insn_yield, 59 }; 60 61 struct insn { 62 enum opcode opcode; 63 u32 match; 64 enum fields fields; 65 }; 66 67 static inline u32 build_rs(u32 arg) 68 { 69 WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n"); 70 71 return (arg & RS_MASK) << RS_SH; 72 } 73 74 static inline u32 build_rt(u32 arg) 75 { 76 WARN(arg & ~RT_MASK, KERN_WARNING "Micro-assembler field overflow\n"); 77 78 return (arg & RT_MASK) << RT_SH; 79 } 80 81 static inline u32 build_rd(u32 arg) 82 { 83 WARN(arg & ~RD_MASK, KERN_WARNING "Micro-assembler field overflow\n"); 84 85 return (arg & RD_MASK) << RD_SH; 86 } 87 88 static inline u32 build_re(u32 arg) 89 { 90 WARN(arg & ~RE_MASK, KERN_WARNING "Micro-assembler field overflow\n"); 91 92 return (arg & RE_MASK) << RE_SH; 93 } 94 95 static inline u32 build_simm(s32 arg) 96 { 97 WARN(arg > 0x7fff || arg < -0x8000, 98 KERN_WARNING "Micro-assembler field overflow\n"); 99 100 return arg & 0xffff; 101 } 102 103 static inline u32 build_uimm(u32 arg) 104 { 105 WARN(arg & ~IMM_MASK, KERN_WARNING "Micro-assembler field overflow\n"); 106 107 return arg & IMM_MASK; 108 } 109 110 static inline u32 build_scimm(u32 arg) 111 { 112 WARN(arg & ~SCIMM_MASK, 113 KERN_WARNING "Micro-assembler field overflow\n"); 114 115 return (arg & SCIMM_MASK) << SCIMM_SH; 116 } 117 118 static inline u32 build_func(u32 arg) 119 { 120 WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n"); 121 122 return arg & FUNC_MASK; 123 } 124 125 static inline u32 build_set(u32 arg) 126 { 127 WARN(arg & ~SET_MASK, KERN_WARNING "Micro-assembler field overflow\n"); 128 129 return arg & SET_MASK; 130 } 131 132 static void build_insn(u32 **buf, enum opcode opc, ...); 133 134 #define I_u1u2u3(op) \ 135 Ip_u1u2u3(op) \ 136 { \ 137 build_insn(buf, insn##op, a, b, c); \ 138 } \ 139 UASM_EXPORT_SYMBOL(uasm_i##op); 140 141 #define I_u2u1u3(op) \ 142 Ip_u2u1u3(op) \ 143 { \ 144 build_insn(buf, insn##op, b, a, c); \ 145 } \ 146 UASM_EXPORT_SYMBOL(uasm_i##op); 147 148 #define I_u3u2u1(op) \ 149 Ip_u3u2u1(op) \ 150 { \ 151 build_insn(buf, insn##op, c, b, a); \ 152 } \ 153 UASM_EXPORT_SYMBOL(uasm_i##op); 154 155 #define I_u3u1u2(op) \ 156 Ip_u3u1u2(op) \ 157 { \ 158 build_insn(buf, insn##op, b, c, a); \ 159 } \ 160 UASM_EXPORT_SYMBOL(uasm_i##op); 161 162 #define I_u1u2s3(op) \ 163 Ip_u1u2s3(op) \ 164 { \ 165 build_insn(buf, insn##op, a, b, c); \ 166 } \ 167 UASM_EXPORT_SYMBOL(uasm_i##op); 168 169 #define I_u2s3u1(op) \ 170 Ip_u2s3u1(op) \ 171 { \ 172 build_insn(buf, insn##op, c, a, b); \ 173 } \ 174 UASM_EXPORT_SYMBOL(uasm_i##op); 175 176 #define I_u2u1s3(op) \ 177 Ip_u2u1s3(op) \ 178 { \ 179 build_insn(buf, insn##op, b, a, c); \ 180 } \ 181 UASM_EXPORT_SYMBOL(uasm_i##op); 182 183 #define I_u2u1msbu3(op) \ 184 Ip_u2u1msbu3(op) \ 185 { \ 186 build_insn(buf, insn##op, b, a, c+d-1, c); \ 187 } \ 188 UASM_EXPORT_SYMBOL(uasm_i##op); 189 190 #define I_u2u1msb32u3(op) \ 191 Ip_u2u1msbu3(op) \ 192 { \ 193 build_insn(buf, insn##op, b, a, c+d-33, c); \ 194 } \ 195 UASM_EXPORT_SYMBOL(uasm_i##op); 196 197 #define I_u2u1msbdu3(op) \ 198 Ip_u2u1msbu3(op) \ 199 { \ 200 build_insn(buf, insn##op, b, a, d-1, c); \ 201 } \ 202 UASM_EXPORT_SYMBOL(uasm_i##op); 203 204 #define I_u1u2(op) \ 205 Ip_u1u2(op) \ 206 { \ 207 build_insn(buf, insn##op, a, b); \ 208 } \ 209 UASM_EXPORT_SYMBOL(uasm_i##op); 210 211 #define I_u2u1(op) \ 212 Ip_u1u2(op) \ 213 { \ 214 build_insn(buf, insn##op, b, a); \ 215 } \ 216 UASM_EXPORT_SYMBOL(uasm_i##op); 217 218 #define I_u1s2(op) \ 219 Ip_u1s2(op) \ 220 { \ 221 build_insn(buf, insn##op, a, b); \ 222 } \ 223 UASM_EXPORT_SYMBOL(uasm_i##op); 224 225 #define I_u1(op) \ 226 Ip_u1(op) \ 227 { \ 228 build_insn(buf, insn##op, a); \ 229 } \ 230 UASM_EXPORT_SYMBOL(uasm_i##op); 231 232 #define I_0(op) \ 233 Ip_0(op) \ 234 { \ 235 build_insn(buf, insn##op); \ 236 } \ 237 UASM_EXPORT_SYMBOL(uasm_i##op); 238 239 I_u2u1s3(_addiu) 240 I_u3u1u2(_addu) 241 I_u2u1u3(_andi) 242 I_u3u1u2(_and) 243 I_u1u2s3(_beq) 244 I_u1u2s3(_beql) 245 I_u1s2(_bgez) 246 I_u1s2(_bgezl) 247 I_u1s2(_bltz) 248 I_u1s2(_bltzl) 249 I_u1u2s3(_bne) 250 I_u2s3u1(_cache) 251 I_u1u2u3(_dmfc0) 252 I_u1u2u3(_dmtc0) 253 I_u2u1s3(_daddiu) 254 I_u3u1u2(_daddu) 255 I_u1u2(_divu) 256 I_u2u1u3(_dsll) 257 I_u2u1u3(_dsll32) 258 I_u2u1u3(_dsra) 259 I_u2u1u3(_dsrl) 260 I_u2u1u3(_dsrl32) 261 I_u2u1u3(_drotr) 262 I_u2u1u3(_drotr32) 263 I_u3u1u2(_dsubu) 264 I_0(_eret) 265 I_u2u1msbdu3(_ext) 266 I_u2u1msbu3(_ins) 267 I_u1(_j) 268 I_u1(_jal) 269 I_u2u1(_jalr) 270 I_u1(_jr) 271 I_u2s3u1(_ld) 272 I_u2s3u1(_lh) 273 I_u2s3u1(_ll) 274 I_u2s3u1(_lld) 275 I_u1s2(_lui) 276 I_u2s3u1(_lw) 277 I_u1u2u3(_mfc0) 278 I_u1(_mfhi) 279 I_u1u2u3(_mtc0) 280 I_u3u1u2(_mul) 281 I_u2u1u3(_ori) 282 I_u3u1u2(_or) 283 I_0(_rfe) 284 I_u2s3u1(_sc) 285 I_u2s3u1(_scd) 286 I_u2s3u1(_sd) 287 I_u2u1u3(_sll) 288 I_u3u2u1(_sllv) 289 I_u2u1s3(_sltiu) 290 I_u3u1u2(_sltu) 291 I_u2u1u3(_sra) 292 I_u2u1u3(_srl) 293 I_u3u2u1(_srlv) 294 I_u2u1u3(_rotr) 295 I_u3u1u2(_subu) 296 I_u2s3u1(_sw) 297 I_u1(_sync) 298 I_0(_tlbp) 299 I_0(_tlbr) 300 I_0(_tlbwi) 301 I_0(_tlbwr) 302 I_u1(_wait); 303 I_u2u1(_wsbh) 304 I_u3u1u2(_xor) 305 I_u2u1u3(_xori) 306 I_u2u1(_yield) 307 I_u2u1msbu3(_dins); 308 I_u2u1msb32u3(_dinsm); 309 I_u1(_syscall); 310 I_u1u2s3(_bbit0); 311 I_u1u2s3(_bbit1); 312 I_u3u1u2(_lwx) 313 I_u3u1u2(_ldx) 314 315 #ifdef CONFIG_CPU_CAVIUM_OCTEON 316 #include <asm/octeon/octeon.h> 317 void ISAFUNC(uasm_i_pref)(u32 **buf, unsigned int a, signed int b, 318 unsigned int c) 319 { 320 if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) && a <= 24 && a != 5) 321 /* 322 * As per erratum Core-14449, replace prefetches 0-4, 323 * 6-24 with 'pref 28'. 324 */ 325 build_insn(buf, insn_pref, c, 28, b); 326 else 327 build_insn(buf, insn_pref, c, a, b); 328 } 329 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_i_pref)); 330 #else 331 I_u2s3u1(_pref) 332 #endif 333 334 /* Handle labels. */ 335 void ISAFUNC(uasm_build_label)(struct uasm_label **lab, u32 *addr, int lid) 336 { 337 (*lab)->addr = addr; 338 (*lab)->lab = lid; 339 (*lab)++; 340 } 341 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_build_label)); 342 343 int ISAFUNC(uasm_in_compat_space_p)(long addr) 344 { 345 /* Is this address in 32bit compat space? */ 346 #ifdef CONFIG_64BIT 347 return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L); 348 #else 349 return 1; 350 #endif 351 } 352 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_in_compat_space_p)); 353 354 static int uasm_rel_highest(long val) 355 { 356 #ifdef CONFIG_64BIT 357 return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000; 358 #else 359 return 0; 360 #endif 361 } 362 363 static int uasm_rel_higher(long val) 364 { 365 #ifdef CONFIG_64BIT 366 return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000; 367 #else 368 return 0; 369 #endif 370 } 371 372 int ISAFUNC(uasm_rel_hi)(long val) 373 { 374 return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000; 375 } 376 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_hi)); 377 378 int ISAFUNC(uasm_rel_lo)(long val) 379 { 380 return ((val & 0xffff) ^ 0x8000) - 0x8000; 381 } 382 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_lo)); 383 384 void ISAFUNC(UASM_i_LA_mostly)(u32 **buf, unsigned int rs, long addr) 385 { 386 if (!ISAFUNC(uasm_in_compat_space_p)(addr)) { 387 ISAFUNC(uasm_i_lui)(buf, rs, uasm_rel_highest(addr)); 388 if (uasm_rel_higher(addr)) 389 ISAFUNC(uasm_i_daddiu)(buf, rs, rs, uasm_rel_higher(addr)); 390 if (ISAFUNC(uasm_rel_hi(addr))) { 391 ISAFUNC(uasm_i_dsll)(buf, rs, rs, 16); 392 ISAFUNC(uasm_i_daddiu)(buf, rs, rs, 393 ISAFUNC(uasm_rel_hi)(addr)); 394 ISAFUNC(uasm_i_dsll)(buf, rs, rs, 16); 395 } else 396 ISAFUNC(uasm_i_dsll32)(buf, rs, rs, 0); 397 } else 398 ISAFUNC(uasm_i_lui)(buf, rs, ISAFUNC(uasm_rel_hi(addr))); 399 } 400 UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA_mostly)); 401 402 void ISAFUNC(UASM_i_LA)(u32 **buf, unsigned int rs, long addr) 403 { 404 ISAFUNC(UASM_i_LA_mostly)(buf, rs, addr); 405 if (ISAFUNC(uasm_rel_lo(addr))) { 406 if (!ISAFUNC(uasm_in_compat_space_p)(addr)) 407 ISAFUNC(uasm_i_daddiu)(buf, rs, rs, 408 ISAFUNC(uasm_rel_lo(addr))); 409 else 410 ISAFUNC(uasm_i_addiu)(buf, rs, rs, 411 ISAFUNC(uasm_rel_lo(addr))); 412 } 413 } 414 UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA)); 415 416 /* Handle relocations. */ 417 void ISAFUNC(uasm_r_mips_pc16)(struct uasm_reloc **rel, u32 *addr, int lid) 418 { 419 (*rel)->addr = addr; 420 (*rel)->type = R_MIPS_PC16; 421 (*rel)->lab = lid; 422 (*rel)++; 423 } 424 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_r_mips_pc16)); 425 426 static inline void __resolve_relocs(struct uasm_reloc *rel, 427 struct uasm_label *lab); 428 429 void ISAFUNC(uasm_resolve_relocs)(struct uasm_reloc *rel, 430 struct uasm_label *lab) 431 { 432 struct uasm_label *l; 433 434 for (; rel->lab != UASM_LABEL_INVALID; rel++) 435 for (l = lab; l->lab != UASM_LABEL_INVALID; l++) 436 if (rel->lab == l->lab) 437 __resolve_relocs(rel, l); 438 } 439 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_resolve_relocs)); 440 441 void ISAFUNC(uasm_move_relocs)(struct uasm_reloc *rel, u32 *first, u32 *end, 442 long off) 443 { 444 for (; rel->lab != UASM_LABEL_INVALID; rel++) 445 if (rel->addr >= first && rel->addr < end) 446 rel->addr += off; 447 } 448 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_relocs)); 449 450 void ISAFUNC(uasm_move_labels)(struct uasm_label *lab, u32 *first, u32 *end, 451 long off) 452 { 453 for (; lab->lab != UASM_LABEL_INVALID; lab++) 454 if (lab->addr >= first && lab->addr < end) 455 lab->addr += off; 456 } 457 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_labels)); 458 459 void ISAFUNC(uasm_copy_handler)(struct uasm_reloc *rel, struct uasm_label *lab, 460 u32 *first, u32 *end, u32 *target) 461 { 462 long off = (long)(target - first); 463 464 memcpy(target, first, (end - first) * sizeof(u32)); 465 466 ISAFUNC(uasm_move_relocs(rel, first, end, off)); 467 ISAFUNC(uasm_move_labels(lab, first, end, off)); 468 } 469 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_copy_handler)); 470 471 int ISAFUNC(uasm_insn_has_bdelay)(struct uasm_reloc *rel, u32 *addr) 472 { 473 for (; rel->lab != UASM_LABEL_INVALID; rel++) { 474 if (rel->addr == addr 475 && (rel->type == R_MIPS_PC16 476 || rel->type == R_MIPS_26)) 477 return 1; 478 } 479 480 return 0; 481 } 482 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_insn_has_bdelay)); 483 484 /* Convenience functions for labeled branches. */ 485 void ISAFUNC(uasm_il_bltz)(u32 **p, struct uasm_reloc **r, unsigned int reg, 486 int lid) 487 { 488 uasm_r_mips_pc16(r, *p, lid); 489 ISAFUNC(uasm_i_bltz)(p, reg, 0); 490 } 491 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bltz)); 492 493 void ISAFUNC(uasm_il_b)(u32 **p, struct uasm_reloc **r, int lid) 494 { 495 uasm_r_mips_pc16(r, *p, lid); 496 ISAFUNC(uasm_i_b)(p, 0); 497 } 498 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_b)); 499 500 void ISAFUNC(uasm_il_beq)(u32 **p, struct uasm_reloc **r, unsigned int r1, 501 unsigned int r2, int lid) 502 { 503 uasm_r_mips_pc16(r, *p, lid); 504 ISAFUNC(uasm_i_beq)(p, r1, r2, 0); 505 } 506 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beq)); 507 508 void ISAFUNC(uasm_il_beqz)(u32 **p, struct uasm_reloc **r, unsigned int reg, 509 int lid) 510 { 511 uasm_r_mips_pc16(r, *p, lid); 512 ISAFUNC(uasm_i_beqz)(p, reg, 0); 513 } 514 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqz)); 515 516 void ISAFUNC(uasm_il_beqzl)(u32 **p, struct uasm_reloc **r, unsigned int reg, 517 int lid) 518 { 519 uasm_r_mips_pc16(r, *p, lid); 520 ISAFUNC(uasm_i_beqzl)(p, reg, 0); 521 } 522 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqzl)); 523 524 void ISAFUNC(uasm_il_bne)(u32 **p, struct uasm_reloc **r, unsigned int reg1, 525 unsigned int reg2, int lid) 526 { 527 uasm_r_mips_pc16(r, *p, lid); 528 ISAFUNC(uasm_i_bne)(p, reg1, reg2, 0); 529 } 530 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bne)); 531 532 void ISAFUNC(uasm_il_bnez)(u32 **p, struct uasm_reloc **r, unsigned int reg, 533 int lid) 534 { 535 uasm_r_mips_pc16(r, *p, lid); 536 ISAFUNC(uasm_i_bnez)(p, reg, 0); 537 } 538 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bnez)); 539 540 void ISAFUNC(uasm_il_bgezl)(u32 **p, struct uasm_reloc **r, unsigned int reg, 541 int lid) 542 { 543 uasm_r_mips_pc16(r, *p, lid); 544 ISAFUNC(uasm_i_bgezl)(p, reg, 0); 545 } 546 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgezl)); 547 548 void ISAFUNC(uasm_il_bgez)(u32 **p, struct uasm_reloc **r, unsigned int reg, 549 int lid) 550 { 551 uasm_r_mips_pc16(r, *p, lid); 552 ISAFUNC(uasm_i_bgez)(p, reg, 0); 553 } 554 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgez)); 555 556 void ISAFUNC(uasm_il_bbit0)(u32 **p, struct uasm_reloc **r, unsigned int reg, 557 unsigned int bit, int lid) 558 { 559 uasm_r_mips_pc16(r, *p, lid); 560 ISAFUNC(uasm_i_bbit0)(p, reg, bit, 0); 561 } 562 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit0)); 563 564 void ISAFUNC(uasm_il_bbit1)(u32 **p, struct uasm_reloc **r, unsigned int reg, 565 unsigned int bit, int lid) 566 { 567 uasm_r_mips_pc16(r, *p, lid); 568 ISAFUNC(uasm_i_bbit1)(p, reg, bit, 0); 569 } 570 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit1)); 571