aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/mm/uasm-mips.c
diff options
context:
space:
mode:
authorSteven J. Hill <sjhill@mips.com>2013-02-05 17:52:01 -0500
committerSteven J. Hill <Steven.Hill@imgtec.com>2013-05-01 17:32:45 -0400
commitabc597fe623cfd7d3b18d5235c54f3d567d2c3d3 (patch)
tree05ef12f30fc686793522a5fcb7b4ff4a14390088 /arch/mips/mm/uasm-mips.c
parent2aa9fd06e221da4e69693dc1b5c6c6bc84c76f32 (diff)
MIPS: microMIPS: uasm: Split 'uasm.c' into two files.
Split 'uasm.c' into two files. The new file 'uasm-mips.c' has the functions specific to the classic MIPS ISA. The 'uasm.c' file contains common code that can be used by classic or other ISAs that could be supported by the kernel. Signed-off-by: Steven J. Hill <sjhill@mips.com> Cc: linux-mips@linux-mips.org Cc: cernekee@gmail.com Cc: kevink@paralogos.com Cc: ddaney.cavm@gmail.com Patchwork: https://patchwork.linux-mips.org/patch/4922/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org> (cherry picked from commit 0961103562ab958fa74f35043bf4f72e51ed6155)
Diffstat (limited to 'arch/mips/mm/uasm-mips.c')
-rw-r--r--arch/mips/mm/uasm-mips.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/arch/mips/mm/uasm-mips.c b/arch/mips/mm/uasm-mips.c
new file mode 100644
index 000000000000..e78e74dc3aea
--- /dev/null
+++ b/arch/mips/mm/uasm-mips.c
@@ -0,0 +1,196 @@
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#include <linux/kernel.h>
17#include <linux/types.h>
18#include <linux/init.h>
19
20#include <asm/inst.h>
21#include <asm/elf.h>
22#include <asm/bugs.h>
23#include <asm/uasm.h>
24
25#define RS_MASK 0x1f
26#define RS_SH 21
27#define RT_MASK 0x1f
28#define RT_SH 16
29#define SCIMM_MASK 0xfffff
30#define SCIMM_SH 6
31
32/* This macro sets the non-variable bits of an instruction. */
33#define M(a, b, c, d, e, f) \
34 ((a) << OP_SH \
35 | (b) << RS_SH \
36 | (c) << RT_SH \
37 | (d) << RD_SH \
38 | (e) << RE_SH \
39 | (f) << FUNC_SH)
40
41#include "uasm.c"
42
43static struct insn insn_table[] __uasminitdata = {
44 { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
45 { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
46 { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
47 { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
48 { insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
49 { insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
50 { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
51 { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
52 { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
53 { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
54 { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
55 { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
56 { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
57 { insn_cache, M(cache_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
58 { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
59 { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
60 { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
61 { insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
62 { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
63 { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
64 { insn_drotr32, M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE },
65 { insn_drotr, M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE },
66 { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
67 { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
68 { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
69 { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
70 { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
71 { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
72 { insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 },
73 { insn_ext, M(spec3_op, 0, 0, 0, 0, ext_op), RS | RT | RD | RE },
74 { insn_ins, M(spec3_op, 0, 0, 0, 0, ins_op), RS | RT | RD | RE },
75 { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
76 { insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM },
77 { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
78 { insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS },
79 { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
80 { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
81 { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
82 { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
83 { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM },
84 { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
85 { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
86 { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET},
87 { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET},
88 { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
89 { insn_or, M(spec_op, 0, 0, 0, 0, or_op), RS | RT | RD },
90 { insn_pref, M(pref_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
91 { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 },
92 { insn_rotr, M(spec_op, 1, 0, 0, 0, srl_op), RT | RD | RE },
93 { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
94 { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
95 { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
96 { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE },
97 { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE },
98 { insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE },
99 { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD },
100 { insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
101 { insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
102 { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 },
103 { insn_tlbr, M(cop0_op, cop_op, 0, 0, 0, tlbr_op), 0 },
104 { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 },
105 { insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 },
106 { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
107 { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD },
108 { insn_invalid, 0, 0 }
109};
110
111#undef M
112
113static inline __uasminit u32 build_bimm(s32 arg)
114{
115 WARN(arg > 0x1ffff || arg < -0x20000,
116 KERN_WARNING "Micro-assembler field overflow\n");
117
118 WARN(arg & 0x3, KERN_WARNING "Invalid micro-assembler branch target\n");
119
120 return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
121}
122
123static inline __uasminit u32 build_jimm(u32 arg)
124{
125 WARN(arg & ~(JIMM_MASK << 2),
126 KERN_WARNING "Micro-assembler field overflow\n");
127
128 return (arg >> 2) & JIMM_MASK;
129}
130
131/*
132 * The order of opcode arguments is implicitly left to right,
133 * starting with RS and ending with FUNC or IMM.
134 */
135static void __uasminit build_insn(u32 **buf, enum opcode opc, ...)
136{
137 struct insn *ip = NULL;
138 unsigned int i;
139 va_list ap;
140 u32 op;
141
142 for (i = 0; insn_table[i].opcode != insn_invalid; i++)
143 if (insn_table[i].opcode == opc) {
144 ip = &insn_table[i];
145 break;
146 }
147
148 if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
149 panic("Unsupported Micro-assembler instruction %d", opc);
150
151 op = ip->match;
152 va_start(ap, opc);
153 if (ip->fields & RS)
154 op |= build_rs(va_arg(ap, u32));
155 if (ip->fields & RT)
156 op |= build_rt(va_arg(ap, u32));
157 if (ip->fields & RD)
158 op |= build_rd(va_arg(ap, u32));
159 if (ip->fields & RE)
160 op |= build_re(va_arg(ap, u32));
161 if (ip->fields & SIMM)
162 op |= build_simm(va_arg(ap, s32));
163 if (ip->fields & UIMM)
164 op |= build_uimm(va_arg(ap, u32));
165 if (ip->fields & BIMM)
166 op |= build_bimm(va_arg(ap, s32));
167 if (ip->fields & JIMM)
168 op |= build_jimm(va_arg(ap, u32));
169 if (ip->fields & FUNC)
170 op |= build_func(va_arg(ap, u32));
171 if (ip->fields & SET)
172 op |= build_set(va_arg(ap, u32));
173 if (ip->fields & SCIMM)
174 op |= build_scimm(va_arg(ap, u32));
175 va_end(ap);
176
177 **buf = op;
178 (*buf)++;
179}
180
181static inline void __uasminit
182__resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
183{
184 long laddr = (long)lab->addr;
185 long raddr = (long)rel->addr;
186
187 switch (rel->type) {
188 case R_MIPS_PC16:
189 *rel->addr |= build_bimm(laddr - (raddr + 4));
190 break;
191
192 default:
193 panic("Unsupported Micro-assembler relocation %d",
194 rel->type);
195 }
196}