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