1 /*
2 * Tiny Code Generator for QEMU
3 *
4 * Copyright (c) 2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 #include "qemu/osdep.h"
25 #include "qemu/host-utils.h"
26 #include "cpu.h"
27 #include "exec/helper-proto.h"
28 #include "exec/cpu_ldst.h"
29 #include "exec/exec-all.h"
30 #include "exec/tb-lookup.h"
31 #include "disas/disas.h"
32 #include "exec/log.h"
33 #include "tcg/tcg.h"
34 #ifdef TARGET_CHERI
35 #include "cheri-helper-utils.h"
36 #endif
37
38 /* 32-bit helpers */
39
HELPER(div_i32)40 int32_t HELPER(div_i32)(int32_t arg1, int32_t arg2)
41 {
42 return arg1 / arg2;
43 }
44
HELPER(rem_i32)45 int32_t HELPER(rem_i32)(int32_t arg1, int32_t arg2)
46 {
47 return arg1 % arg2;
48 }
49
HELPER(divu_i32)50 uint32_t HELPER(divu_i32)(uint32_t arg1, uint32_t arg2)
51 {
52 return arg1 / arg2;
53 }
54
HELPER(remu_i32)55 uint32_t HELPER(remu_i32)(uint32_t arg1, uint32_t arg2)
56 {
57 return arg1 % arg2;
58 }
59
60 /* 64-bit helpers */
61
HELPER(shl_i64)62 uint64_t HELPER(shl_i64)(uint64_t arg1, uint64_t arg2)
63 {
64 return arg1 << arg2;
65 }
66
HELPER(shr_i64)67 uint64_t HELPER(shr_i64)(uint64_t arg1, uint64_t arg2)
68 {
69 return arg1 >> arg2;
70 }
71
HELPER(sar_i64)72 int64_t HELPER(sar_i64)(int64_t arg1, int64_t arg2)
73 {
74 return arg1 >> arg2;
75 }
76
HELPER(div_i64)77 int64_t HELPER(div_i64)(int64_t arg1, int64_t arg2)
78 {
79 return arg1 / arg2;
80 }
81
HELPER(rem_i64)82 int64_t HELPER(rem_i64)(int64_t arg1, int64_t arg2)
83 {
84 return arg1 % arg2;
85 }
86
HELPER(divu_i64)87 uint64_t HELPER(divu_i64)(uint64_t arg1, uint64_t arg2)
88 {
89 return arg1 / arg2;
90 }
91
HELPER(remu_i64)92 uint64_t HELPER(remu_i64)(uint64_t arg1, uint64_t arg2)
93 {
94 return arg1 % arg2;
95 }
96
HELPER(muluh_i64)97 uint64_t HELPER(muluh_i64)(uint64_t arg1, uint64_t arg2)
98 {
99 uint64_t l, h;
100 mulu64(&l, &h, arg1, arg2);
101 return h;
102 }
103
HELPER(mulsh_i64)104 int64_t HELPER(mulsh_i64)(int64_t arg1, int64_t arg2)
105 {
106 uint64_t l, h;
107 muls64(&l, &h, arg1, arg2);
108 return h;
109 }
110
HELPER(clz_i32)111 uint32_t HELPER(clz_i32)(uint32_t arg, uint32_t zero_val)
112 {
113 return arg ? clz32(arg) : zero_val;
114 }
115
HELPER(ctz_i32)116 uint32_t HELPER(ctz_i32)(uint32_t arg, uint32_t zero_val)
117 {
118 return arg ? ctz32(arg) : zero_val;
119 }
120
HELPER(clz_i64)121 uint64_t HELPER(clz_i64)(uint64_t arg, uint64_t zero_val)
122 {
123 return arg ? clz64(arg) : zero_val;
124 }
125
HELPER(ctz_i64)126 uint64_t HELPER(ctz_i64)(uint64_t arg, uint64_t zero_val)
127 {
128 return arg ? ctz64(arg) : zero_val;
129 }
130
HELPER(clrsb_i32)131 uint32_t HELPER(clrsb_i32)(uint32_t arg)
132 {
133 return clrsb32(arg);
134 }
135
HELPER(clrsb_i64)136 uint64_t HELPER(clrsb_i64)(uint64_t arg)
137 {
138 return clrsb64(arg);
139 }
140
HELPER(ctpop_i32)141 uint32_t HELPER(ctpop_i32)(uint32_t arg)
142 {
143 return ctpop32(arg);
144 }
145
HELPER(ctpop_i64)146 uint64_t HELPER(ctpop_i64)(uint64_t arg)
147 {
148 return ctpop64(arg);
149 }
150
HELPER(lookup_tb_ptr)151 void *HELPER(lookup_tb_ptr)(CPUArchState *env)
152 {
153 CPUState *cpu = env_cpu(env);
154 TranslationBlock *tb;
155 target_ulong cs_base, pc;
156 uint32_t flags;
157
158 tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, curr_cflags());
159 if (tb == NULL) {
160 return tcg_ctx->code_gen_epilogue;
161 }
162 qemu_log_mask_and_addr(CPU_LOG_EXEC, pc,
163 "Chain %d: %p ["
164 TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n",
165 cpu->cpu_index, tb->tc.ptr, cs_base, pc, flags,
166 lookup_symbol(pc));
167 return tb->tc.ptr;
168 }
169
170 #if defined(CONFIG_MIPS_LOG_INSTR)
171 /*
172 * Print the instruction to log file.
173 */
HELPER(log_instruction)174 void HELPER(log_instruction)(CPUArchState *env, target_ulong pc)
175 {
176 if (unlikely(qemu_loglevel_mask(CPU_LOG_INSTR) && qemu_log_in_addr_range(pc))) {
177 #if defined(CONFIG_RVFI_DII) && defined(TARGET_RISCV)
178 if (env->rvfi_dii_have_injected_insn) {
179 uint32_t insn = env->rvfi_dii_trace.rvfi_dii_insn;
180 target_disas_buf(stderr, env_cpu(env), &insn, sizeof(insn),
181 PC_ADDR(env), 1);
182 } else
183 #endif
184 {
185 /* Disassemble and print one instruction. */
186 log_target_disas(env_cpu(env), pc, -1);
187 }
188 }
189 }
190
191 #ifdef TARGET_MIPS
192 /*
193 * dump non-capability data to cvtrace entry
194 */
cvtrace_dump_gpr_ldst(cvtrace_t * cvtrace,uint8_t version,uint64_t addr,uint64_t value)195 static inline void cvtrace_dump_gpr_ldst(cvtrace_t *cvtrace, uint8_t version,
196 uint64_t addr, uint64_t value)
197 {
198 if (qemu_loglevel_mask(CPU_LOG_CVTRACE)) {
199 cvtrace->version = version;
200 cvtrace->val1 = tswap64(addr);
201 cvtrace->val2 = tswap64(value);
202 }
203 }
204 #define cvtrace_dump_gpr_load(trace, addr, val) \
205 cvtrace_dump_gpr_ldst(trace, CVT_LD_GPR, addr, val)
206 #define cvtrace_dump_gpr_store(trace, addr, val) \
207 cvtrace_dump_gpr_ldst(trace, CVT_ST_GPR, addr, val)
208 #endif
209
210 /*
211 * Print the memory store to log file.
212 */
HELPER(dump_store64)213 void HELPER(dump_store64)(CPUArchState *env, target_ulong addr, uint64_t value, MemOp op)
214 {
215
216 if (likely(!(qemu_loglevel_mask(CPU_LOG_INSTR | CPU_LOG_CVTRACE))))
217 return;
218
219 #ifdef TARGET_CHERI
220 // Try not to dump all stores when -dfilter is enabled
221 // Note: we check both PC and memory location in -dfilter
222 if (likely(!should_log_mem_access(env, CPU_LOG_INSTR | CPU_LOG_CVTRACE, addr)))
223 return;
224 #endif
225
226 #ifdef TARGET_MIPS
227 if (qemu_loglevel_mask(CPU_LOG_CVTRACE)) {
228 cvtrace_dump_gpr_store(&env->cvtrace, addr, value);
229 return;
230 }
231 #endif
232
233 // FIXME: value printed is not correct for sdl!
234 // FIXME: value printed is not correct for sdr!
235 // FIXME: value printed is not correct for swl!
236 // FIXME: value printed is not correct for swr!
237 switch (memop_size(op)) {
238 case 8:
239 qemu_log(" Memory Write [" TARGET_FMT_lx "] = " TARGET_FMT_plx "\n",
240 addr, value);
241 break;
242 case 4:
243 qemu_log(" Memory Write [" TARGET_FMT_lx "] = %08x\n", addr,
244 (uint32_t)value);
245 break;
246 case 2:
247 qemu_log(" Memory Write [" TARGET_FMT_lx "] = %04x\n", addr,
248 (uint16_t)value);
249 break;
250 case 1:
251 qemu_log(" Memory Write [" TARGET_FMT_lx "] = %02x\n", addr,
252 (uint8_t)value);
253 break;
254 default:
255 tcg_abort();
256 }
257 }
258
HELPER(dump_store32)259 void HELPER(dump_store32)(CPUArchState *env, target_ulong addr, uint32_t value, MemOp op)
260 {
261 helper_dump_store64(env, addr, (uint64_t)value, op);
262 }
263
264 /*
265 * Print the memory load to log file.
266 */
HELPER(dump_load64)267 void HELPER(dump_load64)(CPUArchState *env, target_ulong addr, uint64_t value, MemOp op)
268 {
269 if (likely(!(qemu_loglevel_mask(CPU_LOG_INSTR | CPU_LOG_CVTRACE))))
270 return;
271
272 #ifdef TARGET_CHERI
273 // Try not to dump all loads when -dfilter is enabled
274 // Note: we check both PC and memory location in -dfilter
275 if (likely(!should_log_mem_access(env, CPU_LOG_INSTR | CPU_LOG_CVTRACE, addr)))
276 return;
277 #endif
278
279 #ifdef TARGET_MIPS
280 if (qemu_loglevel_mask(CPU_LOG_CVTRACE)) {
281 cvtrace_dump_gpr_load(&env->cvtrace, addr, value);
282 return;
283 }
284 #endif
285 // FIXME: cloadtags not correct
286 switch (memop_size(op)) {
287 case 8:
288 qemu_log(" Memory Read [" TARGET_FMT_lx "] = " TARGET_FMT_plx "\n",
289 addr, value);
290 break;
291 case 4:
292 qemu_log(" Memory Read [" TARGET_FMT_lx "] = %08x\n", addr,
293 (uint32_t)value);
294 break;
295 case 2:
296 qemu_log(" Memory Read [" TARGET_FMT_lx "] = %04x\n", addr,
297 (uint16_t)value);
298 break;
299 case 1:
300
301 qemu_log(" Memory Read [" TARGET_FMT_lx "] = %02x\n", addr,
302 (uint8_t)value);
303 break;
304 default:
305 tcg_abort();
306 }
307 }
308
HELPER(dump_load32)309 void HELPER(dump_load32)(CPUArchState *env, target_ulong addr, uint32_t value, MemOp op)
310 {
311 helper_dump_load64(env, addr, (uint64_t)value, op);
312 }
313 #endif
314
315
HELPER(exit_atomic)316 void HELPER(exit_atomic)(CPUArchState *env)
317 {
318 cpu_loop_exit_atomic(env_cpu(env), GETPC());
319 }
320