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
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.
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.
37 #define IMM_MASK 0xffff
39 #define JIMM_MASK 0x3ffffff
41 #define FUNC_MASK 0x3f
46 #define SIMM9_MASK 0x1ff
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_cfc1
, insn_cfcmsa
, insn_ctc1
, insn_ctcmsa
,
53 insn_daddiu
, insn_daddu
, insn_di
, insn_dins
, insn_dinsm
, insn_divu
,
54 insn_dmfc0
, insn_dmtc0
, insn_drotr
, insn_drotr32
, insn_dsll
,
55 insn_dsll32
, insn_dsra
, insn_dsrl
, insn_dsrl32
, insn_dsubu
, insn_eret
,
56 insn_ext
, insn_ins
, insn_j
, insn_jal
, insn_jalr
, insn_jr
, insn_lb
,
57 insn_ld
, insn_ldx
, insn_lh
, insn_ll
, insn_lld
, insn_lui
, insn_lw
,
58 insn_lwx
, insn_mfc0
, insn_mfhc0
, insn_mfhi
, insn_mflo
, insn_mtc0
,
59 insn_mthc0
, insn_mthi
, insn_mtlo
, insn_mul
, insn_or
, insn_ori
,
60 insn_pref
, insn_rfe
, insn_rotr
, insn_sc
, insn_scd
, insn_sd
, insn_sll
,
61 insn_sllv
, insn_slt
, insn_sltiu
, insn_sltu
, insn_sra
, insn_srl
,
62 insn_srlv
, insn_subu
, insn_sw
, insn_sync
, insn_syscall
, insn_tlbp
,
63 insn_tlbr
, insn_tlbwi
, insn_tlbwr
, insn_wait
, insn_wsbh
, insn_xor
,
64 insn_xori
, insn_yield
, insn_lddir
, insn_ldpte
,
73 static inline u32
build_rs(u32 arg
)
75 WARN(arg
& ~RS_MASK
, KERN_WARNING
"Micro-assembler field overflow\n");
77 return (arg
& RS_MASK
) << RS_SH
;
80 static inline u32
build_rt(u32 arg
)
82 WARN(arg
& ~RT_MASK
, KERN_WARNING
"Micro-assembler field overflow\n");
84 return (arg
& RT_MASK
) << RT_SH
;
87 static inline u32
build_rd(u32 arg
)
89 WARN(arg
& ~RD_MASK
, KERN_WARNING
"Micro-assembler field overflow\n");
91 return (arg
& RD_MASK
) << RD_SH
;
94 static inline u32
build_re(u32 arg
)
96 WARN(arg
& ~RE_MASK
, KERN_WARNING
"Micro-assembler field overflow\n");
98 return (arg
& RE_MASK
) << RE_SH
;
101 static inline u32
build_simm(s32 arg
)
103 WARN(arg
> 0x7fff || arg
< -0x8000,
104 KERN_WARNING
"Micro-assembler field overflow\n");
109 static inline u32
build_uimm(u32 arg
)
111 WARN(arg
& ~IMM_MASK
, KERN_WARNING
"Micro-assembler field overflow\n");
113 return arg
& IMM_MASK
;
116 static inline u32
build_scimm(u32 arg
)
118 WARN(arg
& ~SCIMM_MASK
,
119 KERN_WARNING
"Micro-assembler field overflow\n");
121 return (arg
& SCIMM_MASK
) << SCIMM_SH
;
124 static inline u32
build_scimm9(s32 arg
)
126 WARN((arg
> 0xff || arg
< -0x100),
127 KERN_WARNING
"Micro-assembler field overflow\n");
129 return (arg
& SIMM9_MASK
) << SIMM9_SH
;
132 static inline u32
build_func(u32 arg
)
134 WARN(arg
& ~FUNC_MASK
, KERN_WARNING
"Micro-assembler field overflow\n");
136 return arg
& FUNC_MASK
;
139 static inline u32
build_set(u32 arg
)
141 WARN(arg
& ~SET_MASK
, KERN_WARNING
"Micro-assembler field overflow\n");
143 return arg
& SET_MASK
;
146 static void build_insn(u32
**buf
, enum opcode opc
, ...);
148 #define I_u1u2u3(op) \
151 build_insn(buf, insn##op, a, b, c); \
153 UASM_EXPORT_SYMBOL(uasm_i##op);
155 #define I_s3s1s2(op) \
158 build_insn(buf, insn##op, b, c, a); \
160 UASM_EXPORT_SYMBOL(uasm_i##op);
162 #define I_u2u1u3(op) \
165 build_insn(buf, insn##op, b, a, c); \
167 UASM_EXPORT_SYMBOL(uasm_i##op);
169 #define I_u3u2u1(op) \
172 build_insn(buf, insn##op, c, b, a); \
174 UASM_EXPORT_SYMBOL(uasm_i##op);
176 #define I_u3u1u2(op) \
179 build_insn(buf, insn##op, b, c, a); \
181 UASM_EXPORT_SYMBOL(uasm_i##op);
183 #define I_u1u2s3(op) \
186 build_insn(buf, insn##op, a, b, c); \
188 UASM_EXPORT_SYMBOL(uasm_i##op);
190 #define I_u2s3u1(op) \
193 build_insn(buf, insn##op, c, a, b); \
195 UASM_EXPORT_SYMBOL(uasm_i##op);
197 #define I_u2u1s3(op) \
200 build_insn(buf, insn##op, b, a, c); \
202 UASM_EXPORT_SYMBOL(uasm_i##op);
204 #define I_u2u1msbu3(op) \
207 build_insn(buf, insn##op, b, a, c+d-1, c); \
209 UASM_EXPORT_SYMBOL(uasm_i##op);
211 #define I_u2u1msb32u3(op) \
214 build_insn(buf, insn##op, b, a, c+d-33, c); \
216 UASM_EXPORT_SYMBOL(uasm_i##op);
218 #define I_u2u1msbdu3(op) \
221 build_insn(buf, insn##op, b, a, d-1, c); \
223 UASM_EXPORT_SYMBOL(uasm_i##op);
228 build_insn(buf, insn##op, a, b); \
230 UASM_EXPORT_SYMBOL(uasm_i##op);
235 build_insn(buf, insn##op, b, a); \
237 UASM_EXPORT_SYMBOL(uasm_i##op);
242 build_insn(buf, insn##op, a, b); \
244 UASM_EXPORT_SYMBOL(uasm_i##op);
249 build_insn(buf, insn##op, a); \
251 UASM_EXPORT_SYMBOL(uasm_i##op);
256 build_insn(buf, insn##op); \
258 UASM_EXPORT_SYMBOL(uasm_i##op);
341 I_u2u1msb32u3(_dinsm
);
350 #ifdef CONFIG_CPU_CAVIUM_OCTEON
351 #include <asm/octeon/octeon.h>
352 void ISAFUNC(uasm_i_pref
)(u32
**buf
, unsigned int a
, signed int b
,
355 if (CAVIUM_OCTEON_DCACHE_PREFETCH_WAR
&& a
<= 24 && a
!= 5)
357 * As per erratum Core-14449, replace prefetches 0-4,
358 * 6-24 with 'pref 28'.
360 build_insn(buf
, insn_pref
, c
, 28, b
);
362 build_insn(buf
, insn_pref
, c
, a
, b
);
364 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_i_pref
));
370 void ISAFUNC(uasm_build_label
)(struct uasm_label
**lab
, u32
*addr
, int lid
)
376 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_build_label
));
378 int ISAFUNC(uasm_in_compat_space_p
)(long addr
)
380 /* Is this address in 32bit compat space? */
382 return (((addr
) & 0xffffffff00000000L
) == 0xffffffff00000000L
);
387 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_in_compat_space_p
));
389 static int uasm_rel_highest(long val
)
392 return ((((val
+ 0x800080008000L
) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
398 static int uasm_rel_higher(long val
)
401 return ((((val
+ 0x80008000L
) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
407 int ISAFUNC(uasm_rel_hi
)(long val
)
409 return ((((val
+ 0x8000L
) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
411 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_hi
));
413 int ISAFUNC(uasm_rel_lo
)(long val
)
415 return ((val
& 0xffff) ^ 0x8000) - 0x8000;
417 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_rel_lo
));
419 void ISAFUNC(UASM_i_LA_mostly
)(u32
**buf
, unsigned int rs
, long addr
)
421 if (!ISAFUNC(uasm_in_compat_space_p
)(addr
)) {
422 ISAFUNC(uasm_i_lui
)(buf
, rs
, uasm_rel_highest(addr
));
423 if (uasm_rel_higher(addr
))
424 ISAFUNC(uasm_i_daddiu
)(buf
, rs
, rs
, uasm_rel_higher(addr
));
425 if (ISAFUNC(uasm_rel_hi(addr
))) {
426 ISAFUNC(uasm_i_dsll
)(buf
, rs
, rs
, 16);
427 ISAFUNC(uasm_i_daddiu
)(buf
, rs
, rs
,
428 ISAFUNC(uasm_rel_hi
)(addr
));
429 ISAFUNC(uasm_i_dsll
)(buf
, rs
, rs
, 16);
431 ISAFUNC(uasm_i_dsll32
)(buf
, rs
, rs
, 0);
433 ISAFUNC(uasm_i_lui
)(buf
, rs
, ISAFUNC(uasm_rel_hi(addr
)));
435 UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA_mostly
));
437 void ISAFUNC(UASM_i_LA
)(u32
**buf
, unsigned int rs
, long addr
)
439 ISAFUNC(UASM_i_LA_mostly
)(buf
, rs
, addr
);
440 if (ISAFUNC(uasm_rel_lo(addr
))) {
441 if (!ISAFUNC(uasm_in_compat_space_p
)(addr
))
442 ISAFUNC(uasm_i_daddiu
)(buf
, rs
, rs
,
443 ISAFUNC(uasm_rel_lo(addr
)));
445 ISAFUNC(uasm_i_addiu
)(buf
, rs
, rs
,
446 ISAFUNC(uasm_rel_lo(addr
)));
449 UASM_EXPORT_SYMBOL(ISAFUNC(UASM_i_LA
));
451 /* Handle relocations. */
452 void ISAFUNC(uasm_r_mips_pc16
)(struct uasm_reloc
**rel
, u32
*addr
, int lid
)
455 (*rel
)->type
= R_MIPS_PC16
;
459 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_r_mips_pc16
));
461 static inline void __resolve_relocs(struct uasm_reloc
*rel
,
462 struct uasm_label
*lab
);
464 void ISAFUNC(uasm_resolve_relocs
)(struct uasm_reloc
*rel
,
465 struct uasm_label
*lab
)
467 struct uasm_label
*l
;
469 for (; rel
->lab
!= UASM_LABEL_INVALID
; rel
++)
470 for (l
= lab
; l
->lab
!= UASM_LABEL_INVALID
; l
++)
471 if (rel
->lab
== l
->lab
)
472 __resolve_relocs(rel
, l
);
474 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_resolve_relocs
));
476 void ISAFUNC(uasm_move_relocs
)(struct uasm_reloc
*rel
, u32
*first
, u32
*end
,
479 for (; rel
->lab
!= UASM_LABEL_INVALID
; rel
++)
480 if (rel
->addr
>= first
&& rel
->addr
< end
)
483 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_relocs
));
485 void ISAFUNC(uasm_move_labels
)(struct uasm_label
*lab
, u32
*first
, u32
*end
,
488 for (; lab
->lab
!= UASM_LABEL_INVALID
; lab
++)
489 if (lab
->addr
>= first
&& lab
->addr
< end
)
492 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_move_labels
));
494 void ISAFUNC(uasm_copy_handler
)(struct uasm_reloc
*rel
, struct uasm_label
*lab
,
495 u32
*first
, u32
*end
, u32
*target
)
497 long off
= (long)(target
- first
);
499 memcpy(target
, first
, (end
- first
) * sizeof(u32
));
501 ISAFUNC(uasm_move_relocs(rel
, first
, end
, off
));
502 ISAFUNC(uasm_move_labels(lab
, first
, end
, off
));
504 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_copy_handler
));
506 int ISAFUNC(uasm_insn_has_bdelay
)(struct uasm_reloc
*rel
, u32
*addr
)
508 for (; rel
->lab
!= UASM_LABEL_INVALID
; rel
++) {
509 if (rel
->addr
== addr
510 && (rel
->type
== R_MIPS_PC16
511 || rel
->type
== R_MIPS_26
))
517 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_insn_has_bdelay
));
519 /* Convenience functions for labeled branches. */
520 void ISAFUNC(uasm_il_bltz
)(u32
**p
, struct uasm_reloc
**r
, unsigned int reg
,
523 uasm_r_mips_pc16(r
, *p
, lid
);
524 ISAFUNC(uasm_i_bltz
)(p
, reg
, 0);
526 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bltz
));
528 void ISAFUNC(uasm_il_b
)(u32
**p
, struct uasm_reloc
**r
, int lid
)
530 uasm_r_mips_pc16(r
, *p
, lid
);
531 ISAFUNC(uasm_i_b
)(p
, 0);
533 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_b
));
535 void ISAFUNC(uasm_il_beq
)(u32
**p
, struct uasm_reloc
**r
, unsigned int r1
,
536 unsigned int r2
, int lid
)
538 uasm_r_mips_pc16(r
, *p
, lid
);
539 ISAFUNC(uasm_i_beq
)(p
, r1
, r2
, 0);
541 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beq
));
543 void ISAFUNC(uasm_il_beqz
)(u32
**p
, struct uasm_reloc
**r
, unsigned int reg
,
546 uasm_r_mips_pc16(r
, *p
, lid
);
547 ISAFUNC(uasm_i_beqz
)(p
, reg
, 0);
549 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqz
));
551 void ISAFUNC(uasm_il_beqzl
)(u32
**p
, struct uasm_reloc
**r
, unsigned int reg
,
554 uasm_r_mips_pc16(r
, *p
, lid
);
555 ISAFUNC(uasm_i_beqzl
)(p
, reg
, 0);
557 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_beqzl
));
559 void ISAFUNC(uasm_il_bne
)(u32
**p
, struct uasm_reloc
**r
, unsigned int reg1
,
560 unsigned int reg2
, int lid
)
562 uasm_r_mips_pc16(r
, *p
, lid
);
563 ISAFUNC(uasm_i_bne
)(p
, reg1
, reg2
, 0);
565 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bne
));
567 void ISAFUNC(uasm_il_bnez
)(u32
**p
, struct uasm_reloc
**r
, unsigned int reg
,
570 uasm_r_mips_pc16(r
, *p
, lid
);
571 ISAFUNC(uasm_i_bnez
)(p
, reg
, 0);
573 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bnez
));
575 void ISAFUNC(uasm_il_bgezl
)(u32
**p
, struct uasm_reloc
**r
, unsigned int reg
,
578 uasm_r_mips_pc16(r
, *p
, lid
);
579 ISAFUNC(uasm_i_bgezl
)(p
, reg
, 0);
581 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgezl
));
583 void ISAFUNC(uasm_il_bgez
)(u32
**p
, struct uasm_reloc
**r
, unsigned int reg
,
586 uasm_r_mips_pc16(r
, *p
, lid
);
587 ISAFUNC(uasm_i_bgez
)(p
, reg
, 0);
589 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bgez
));
591 void ISAFUNC(uasm_il_bbit0
)(u32
**p
, struct uasm_reloc
**r
, unsigned int reg
,
592 unsigned int bit
, int lid
)
594 uasm_r_mips_pc16(r
, *p
, lid
);
595 ISAFUNC(uasm_i_bbit0
)(p
, reg
, bit
, 0);
597 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit0
));
599 void ISAFUNC(uasm_il_bbit1
)(u32
**p
, struct uasm_reloc
**r
, unsigned int reg
,
600 unsigned int bit
, int lid
)
602 uasm_r_mips_pc16(r
, *p
, lid
);
603 ISAFUNC(uasm_i_bbit1
)(p
, reg
, bit
, 0);
605 UASM_EXPORT_SYMBOL(ISAFUNC(uasm_il_bbit1
));