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