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