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