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