xref: /qemu/accel/tcg/plugin-gen.c (revision 38b47b19ec3adf6a96d68726dc29096b3aad780a)
1*38b47b19SEmilio G. Cota /*
2*38b47b19SEmilio G. Cota  * plugin-gen.c - TCG-related bits of plugin infrastructure
3*38b47b19SEmilio G. Cota  *
4*38b47b19SEmilio G. Cota  * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
5*38b47b19SEmilio G. Cota  * License: GNU GPL, version 2 or later.
6*38b47b19SEmilio G. Cota  *   See the COPYING file in the top-level directory.
7*38b47b19SEmilio G. Cota  *
8*38b47b19SEmilio G. Cota  * We support instrumentation at an instruction granularity. That is,
9*38b47b19SEmilio G. Cota  * if a plugin wants to instrument the memory accesses performed by a
10*38b47b19SEmilio G. Cota  * particular instruction, it can just do that instead of instrumenting
11*38b47b19SEmilio G. Cota  * all memory accesses. Thus, in order to do this we first have to
12*38b47b19SEmilio G. Cota  * translate a TB, so that plugins can decide what/where to instrument.
13*38b47b19SEmilio G. Cota  *
14*38b47b19SEmilio G. Cota  * Injecting the desired instrumentation could be done with a second
15*38b47b19SEmilio G. Cota  * translation pass that combined the instrumentation requests, but that
16*38b47b19SEmilio G. Cota  * would be ugly and inefficient since we would decode the guest code twice.
17*38b47b19SEmilio G. Cota  * Instead, during TB translation we add "empty" instrumentation calls for all
18*38b47b19SEmilio G. Cota  * possible instrumentation events, and then once we collect the instrumentation
19*38b47b19SEmilio G. Cota  * requests from plugins, we either "fill in" those empty events or remove them
20*38b47b19SEmilio G. Cota  * if they have no requests.
21*38b47b19SEmilio G. Cota  *
22*38b47b19SEmilio G. Cota  * When "filling in" an event we first copy the empty callback's TCG ops. This
23*38b47b19SEmilio G. Cota  * might seem unnecessary, but it is done to support an arbitrary number
24*38b47b19SEmilio G. Cota  * of callbacks per event. Take for example a regular instruction callback.
25*38b47b19SEmilio G. Cota  * We first generate a callback to an empty helper function. Then, if two
26*38b47b19SEmilio G. Cota  * plugins register one callback each for this instruction, we make two copies
27*38b47b19SEmilio G. Cota  * of the TCG ops generated for the empty callback, substituting the function
28*38b47b19SEmilio G. Cota  * pointer that points to the empty helper function with the plugins' desired
29*38b47b19SEmilio G. Cota  * callback functions. After that we remove the empty callback's ops.
30*38b47b19SEmilio G. Cota  *
31*38b47b19SEmilio G. Cota  * Note that the location in TCGOp.args[] of the pointer to a helper function
32*38b47b19SEmilio G. Cota  * varies across different guest and host architectures. Instead of duplicating
33*38b47b19SEmilio G. Cota  * the logic that figures this out, we rely on the fact that the empty
34*38b47b19SEmilio G. Cota  * callbacks point to empty functions that are unique pointers in the program.
35*38b47b19SEmilio G. Cota  * Thus, to find the right location we just have to look for a match in
36*38b47b19SEmilio G. Cota  * TCGOp.args[]. This is the main reason why we first copy an empty callback's
37*38b47b19SEmilio G. Cota  * TCG ops and then fill them in; regardless of whether we have one or many
38*38b47b19SEmilio G. Cota  * callbacks for that event, the logic to add all of them is the same.
39*38b47b19SEmilio G. Cota  *
40*38b47b19SEmilio G. Cota  * When generating more than one callback per event, we make a small
41*38b47b19SEmilio G. Cota  * optimization to avoid generating redundant operations. For instance, for the
42*38b47b19SEmilio G. Cota  * second and all subsequent callbacks of an event, we do not need to reload the
43*38b47b19SEmilio G. Cota  * CPU's index into a TCG temp, since the first callback did it already.
44*38b47b19SEmilio G. Cota  */
45*38b47b19SEmilio G. Cota #include "qemu/osdep.h"
46*38b47b19SEmilio G. Cota #include "cpu.h"
47*38b47b19SEmilio G. Cota #include "tcg/tcg.h"
48*38b47b19SEmilio G. Cota #include "tcg/tcg-op.h"
49*38b47b19SEmilio G. Cota #include "trace/mem.h"
50*38b47b19SEmilio G. Cota #include "exec/exec-all.h"
51*38b47b19SEmilio G. Cota #include "exec/plugin-gen.h"
52*38b47b19SEmilio G. Cota #include "exec/translator.h"
53*38b47b19SEmilio G. Cota 
54*38b47b19SEmilio G. Cota #ifdef CONFIG_SOFTMMU
55*38b47b19SEmilio G. Cota # define CONFIG_SOFTMMU_GATE 1
56*38b47b19SEmilio G. Cota #else
57*38b47b19SEmilio G. Cota # define CONFIG_SOFTMMU_GATE 0
58*38b47b19SEmilio G. Cota #endif
59*38b47b19SEmilio G. Cota 
60*38b47b19SEmilio G. Cota /*
61*38b47b19SEmilio G. Cota  * plugin_cb_start TCG op args[]:
62*38b47b19SEmilio G. Cota  * 0: enum plugin_gen_from
63*38b47b19SEmilio G. Cota  * 1: enum plugin_gen_cb
64*38b47b19SEmilio G. Cota  * 2: set to 1 for mem callback that is a write, 0 otherwise.
65*38b47b19SEmilio G. Cota  */
66*38b47b19SEmilio G. Cota 
67*38b47b19SEmilio G. Cota enum plugin_gen_from {
68*38b47b19SEmilio G. Cota     PLUGIN_GEN_FROM_TB,
69*38b47b19SEmilio G. Cota     PLUGIN_GEN_FROM_INSN,
70*38b47b19SEmilio G. Cota     PLUGIN_GEN_FROM_MEM,
71*38b47b19SEmilio G. Cota     PLUGIN_GEN_AFTER_INSN,
72*38b47b19SEmilio G. Cota     PLUGIN_GEN_N_FROMS,
73*38b47b19SEmilio G. Cota };
74*38b47b19SEmilio G. Cota 
75*38b47b19SEmilio G. Cota enum plugin_gen_cb {
76*38b47b19SEmilio G. Cota     PLUGIN_GEN_CB_UDATA,
77*38b47b19SEmilio G. Cota     PLUGIN_GEN_CB_INLINE,
78*38b47b19SEmilio G. Cota     PLUGIN_GEN_CB_MEM,
79*38b47b19SEmilio G. Cota     PLUGIN_GEN_ENABLE_MEM_HELPER,
80*38b47b19SEmilio G. Cota     PLUGIN_GEN_DISABLE_MEM_HELPER,
81*38b47b19SEmilio G. Cota     PLUGIN_GEN_N_CBS,
82*38b47b19SEmilio G. Cota };
83*38b47b19SEmilio G. Cota 
84*38b47b19SEmilio G. Cota /*
85*38b47b19SEmilio G. Cota  * These helpers are stubs that get dynamically switched out for calls
86*38b47b19SEmilio G. Cota  * direct to the plugin if they are subscribed to.
87*38b47b19SEmilio G. Cota  */
88*38b47b19SEmilio G. Cota void HELPER(plugin_vcpu_udata_cb)(uint32_t cpu_index, void *udata)
89*38b47b19SEmilio G. Cota { }
90*38b47b19SEmilio G. Cota 
91*38b47b19SEmilio G. Cota void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
92*38b47b19SEmilio G. Cota                                 qemu_plugin_meminfo_t info, uint64_t vaddr,
93*38b47b19SEmilio G. Cota                                 void *userdata)
94*38b47b19SEmilio G. Cota { }
95*38b47b19SEmilio G. Cota 
96*38b47b19SEmilio G. Cota static void do_gen_mem_cb(TCGv vaddr, uint32_t info)
97*38b47b19SEmilio G. Cota {
98*38b47b19SEmilio G. Cota     TCGv_i32 cpu_index = tcg_temp_new_i32();
99*38b47b19SEmilio G. Cota     TCGv_i32 meminfo = tcg_const_i32(info);
100*38b47b19SEmilio G. Cota     TCGv_i64 vaddr64 = tcg_temp_new_i64();
101*38b47b19SEmilio G. Cota     TCGv_ptr udata = tcg_const_ptr(NULL);
102*38b47b19SEmilio G. Cota 
103*38b47b19SEmilio G. Cota     tcg_gen_ld_i32(cpu_index, cpu_env,
104*38b47b19SEmilio G. Cota                    -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
105*38b47b19SEmilio G. Cota     tcg_gen_extu_tl_i64(vaddr64, vaddr);
106*38b47b19SEmilio G. Cota 
107*38b47b19SEmilio G. Cota     gen_helper_plugin_vcpu_mem_cb(cpu_index, meminfo, vaddr64, udata);
108*38b47b19SEmilio G. Cota 
109*38b47b19SEmilio G. Cota     tcg_temp_free_ptr(udata);
110*38b47b19SEmilio G. Cota     tcg_temp_free_i64(vaddr64);
111*38b47b19SEmilio G. Cota     tcg_temp_free_i32(meminfo);
112*38b47b19SEmilio G. Cota     tcg_temp_free_i32(cpu_index);
113*38b47b19SEmilio G. Cota }
114*38b47b19SEmilio G. Cota 
115*38b47b19SEmilio G. Cota static void gen_empty_udata_cb(void)
116*38b47b19SEmilio G. Cota {
117*38b47b19SEmilio G. Cota     TCGv_i32 cpu_index = tcg_temp_new_i32();
118*38b47b19SEmilio G. Cota     TCGv_ptr udata = tcg_const_ptr(NULL); /* will be overwritten later */
119*38b47b19SEmilio G. Cota 
120*38b47b19SEmilio G. Cota     tcg_gen_ld_i32(cpu_index, cpu_env,
121*38b47b19SEmilio G. Cota                    -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
122*38b47b19SEmilio G. Cota     gen_helper_plugin_vcpu_udata_cb(cpu_index, udata);
123*38b47b19SEmilio G. Cota 
124*38b47b19SEmilio G. Cota     tcg_temp_free_ptr(udata);
125*38b47b19SEmilio G. Cota     tcg_temp_free_i32(cpu_index);
126*38b47b19SEmilio G. Cota }
127*38b47b19SEmilio G. Cota 
128*38b47b19SEmilio G. Cota /*
129*38b47b19SEmilio G. Cota  * For now we only support addi_i64.
130*38b47b19SEmilio G. Cota  * When we support more ops, we can generate one empty inline cb for each.
131*38b47b19SEmilio G. Cota  */
132*38b47b19SEmilio G. Cota static void gen_empty_inline_cb(void)
133*38b47b19SEmilio G. Cota {
134*38b47b19SEmilio G. Cota     TCGv_i64 val = tcg_temp_new_i64();
135*38b47b19SEmilio G. Cota     TCGv_ptr ptr = tcg_const_ptr(NULL); /* overwritten later */
136*38b47b19SEmilio G. Cota 
137*38b47b19SEmilio G. Cota     tcg_gen_ld_i64(val, ptr, 0);
138*38b47b19SEmilio G. Cota     /* pass an immediate != 0 so that it doesn't get optimized away */
139*38b47b19SEmilio G. Cota     tcg_gen_addi_i64(val, val, 0xdeadface);
140*38b47b19SEmilio G. Cota     tcg_gen_st_i64(val, ptr, 0);
141*38b47b19SEmilio G. Cota     tcg_temp_free_ptr(ptr);
142*38b47b19SEmilio G. Cota     tcg_temp_free_i64(val);
143*38b47b19SEmilio G. Cota }
144*38b47b19SEmilio G. Cota 
145*38b47b19SEmilio G. Cota static void gen_empty_mem_cb(TCGv addr, uint32_t info)
146*38b47b19SEmilio G. Cota {
147*38b47b19SEmilio G. Cota     do_gen_mem_cb(addr, info);
148*38b47b19SEmilio G. Cota }
149*38b47b19SEmilio G. Cota 
150*38b47b19SEmilio G. Cota /*
151*38b47b19SEmilio G. Cota  * Share the same function for enable/disable. When enabling, the NULL
152*38b47b19SEmilio G. Cota  * pointer will be overwritten later.
153*38b47b19SEmilio G. Cota  */
154*38b47b19SEmilio G. Cota static void gen_empty_mem_helper(void)
155*38b47b19SEmilio G. Cota {
156*38b47b19SEmilio G. Cota     TCGv_ptr ptr;
157*38b47b19SEmilio G. Cota 
158*38b47b19SEmilio G. Cota     ptr = tcg_const_ptr(NULL);
159*38b47b19SEmilio G. Cota     tcg_gen_st_ptr(ptr, cpu_env, offsetof(CPUState, plugin_mem_cbs) -
160*38b47b19SEmilio G. Cota                                  offsetof(ArchCPU, env));
161*38b47b19SEmilio G. Cota     tcg_temp_free_ptr(ptr);
162*38b47b19SEmilio G. Cota }
163*38b47b19SEmilio G. Cota 
164*38b47b19SEmilio G. Cota static inline
165*38b47b19SEmilio G. Cota void gen_plugin_cb_start(enum plugin_gen_from from,
166*38b47b19SEmilio G. Cota                          enum plugin_gen_cb type, unsigned wr)
167*38b47b19SEmilio G. Cota {
168*38b47b19SEmilio G. Cota     TCGOp *op;
169*38b47b19SEmilio G. Cota 
170*38b47b19SEmilio G. Cota     tcg_gen_plugin_cb_start(from, type, wr);
171*38b47b19SEmilio G. Cota     op = tcg_last_op();
172*38b47b19SEmilio G. Cota     QSIMPLEQ_INSERT_TAIL(&tcg_ctx->plugin_ops, op, plugin_link);
173*38b47b19SEmilio G. Cota }
174*38b47b19SEmilio G. Cota 
175*38b47b19SEmilio G. Cota static void gen_wrapped(enum plugin_gen_from from,
176*38b47b19SEmilio G. Cota                         enum plugin_gen_cb type, void (*func)(void))
177*38b47b19SEmilio G. Cota {
178*38b47b19SEmilio G. Cota     gen_plugin_cb_start(from, type, 0);
179*38b47b19SEmilio G. Cota     func();
180*38b47b19SEmilio G. Cota     tcg_gen_plugin_cb_end();
181*38b47b19SEmilio G. Cota }
182*38b47b19SEmilio G. Cota 
183*38b47b19SEmilio G. Cota static inline void plugin_gen_empty_callback(enum plugin_gen_from from)
184*38b47b19SEmilio G. Cota {
185*38b47b19SEmilio G. Cota     switch (from) {
186*38b47b19SEmilio G. Cota     case PLUGIN_GEN_AFTER_INSN:
187*38b47b19SEmilio G. Cota         gen_wrapped(from, PLUGIN_GEN_DISABLE_MEM_HELPER,
188*38b47b19SEmilio G. Cota                     gen_empty_mem_helper);
189*38b47b19SEmilio G. Cota         break;
190*38b47b19SEmilio G. Cota     case PLUGIN_GEN_FROM_INSN:
191*38b47b19SEmilio G. Cota         /*
192*38b47b19SEmilio G. Cota          * Note: plugin_gen_inject() relies on ENABLE_MEM_HELPER being
193*38b47b19SEmilio G. Cota          * the first callback of an instruction
194*38b47b19SEmilio G. Cota          */
195*38b47b19SEmilio G. Cota         gen_wrapped(from, PLUGIN_GEN_ENABLE_MEM_HELPER,
196*38b47b19SEmilio G. Cota                     gen_empty_mem_helper);
197*38b47b19SEmilio G. Cota         /* fall through */
198*38b47b19SEmilio G. Cota     case PLUGIN_GEN_FROM_TB:
199*38b47b19SEmilio G. Cota         gen_wrapped(from, PLUGIN_GEN_CB_UDATA, gen_empty_udata_cb);
200*38b47b19SEmilio G. Cota         gen_wrapped(from, PLUGIN_GEN_CB_INLINE, gen_empty_inline_cb);
201*38b47b19SEmilio G. Cota         break;
202*38b47b19SEmilio G. Cota     default:
203*38b47b19SEmilio G. Cota         g_assert_not_reached();
204*38b47b19SEmilio G. Cota     }
205*38b47b19SEmilio G. Cota }
206*38b47b19SEmilio G. Cota 
207*38b47b19SEmilio G. Cota union mem_gen_fn {
208*38b47b19SEmilio G. Cota     void (*mem_fn)(TCGv, uint32_t);
209*38b47b19SEmilio G. Cota     void (*inline_fn)(void);
210*38b47b19SEmilio G. Cota };
211*38b47b19SEmilio G. Cota 
212*38b47b19SEmilio G. Cota static void gen_mem_wrapped(enum plugin_gen_cb type,
213*38b47b19SEmilio G. Cota                             const union mem_gen_fn *f, TCGv addr,
214*38b47b19SEmilio G. Cota                             uint32_t info, bool is_mem)
215*38b47b19SEmilio G. Cota {
216*38b47b19SEmilio G. Cota     int wr = !!(info & TRACE_MEM_ST);
217*38b47b19SEmilio G. Cota 
218*38b47b19SEmilio G. Cota     gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, wr);
219*38b47b19SEmilio G. Cota     if (is_mem) {
220*38b47b19SEmilio G. Cota         f->mem_fn(addr, info);
221*38b47b19SEmilio G. Cota     } else {
222*38b47b19SEmilio G. Cota         f->inline_fn();
223*38b47b19SEmilio G. Cota     }
224*38b47b19SEmilio G. Cota     tcg_gen_plugin_cb_end();
225*38b47b19SEmilio G. Cota }
226*38b47b19SEmilio G. Cota 
227*38b47b19SEmilio G. Cota void plugin_gen_empty_mem_callback(TCGv addr, uint32_t info)
228*38b47b19SEmilio G. Cota {
229*38b47b19SEmilio G. Cota     union mem_gen_fn fn;
230*38b47b19SEmilio G. Cota 
231*38b47b19SEmilio G. Cota     fn.mem_fn = gen_empty_mem_cb;
232*38b47b19SEmilio G. Cota     gen_mem_wrapped(PLUGIN_GEN_CB_MEM, &fn, addr, info, true);
233*38b47b19SEmilio G. Cota 
234*38b47b19SEmilio G. Cota     fn.inline_fn = gen_empty_inline_cb;
235*38b47b19SEmilio G. Cota     gen_mem_wrapped(PLUGIN_GEN_CB_INLINE, &fn, 0, info, false);
236*38b47b19SEmilio G. Cota }
237*38b47b19SEmilio G. Cota 
238*38b47b19SEmilio G. Cota static TCGOp *find_op(TCGOp *op, TCGOpcode opc)
239*38b47b19SEmilio G. Cota {
240*38b47b19SEmilio G. Cota     while (op) {
241*38b47b19SEmilio G. Cota         if (op->opc == opc) {
242*38b47b19SEmilio G. Cota             return op;
243*38b47b19SEmilio G. Cota         }
244*38b47b19SEmilio G. Cota         op = QTAILQ_NEXT(op, link);
245*38b47b19SEmilio G. Cota     }
246*38b47b19SEmilio G. Cota     return NULL;
247*38b47b19SEmilio G. Cota }
248*38b47b19SEmilio G. Cota 
249*38b47b19SEmilio G. Cota static TCGOp *rm_ops_range(TCGOp *begin, TCGOp *end)
250*38b47b19SEmilio G. Cota {
251*38b47b19SEmilio G. Cota     TCGOp *ret = QTAILQ_NEXT(end, link);
252*38b47b19SEmilio G. Cota 
253*38b47b19SEmilio G. Cota     QTAILQ_REMOVE_SEVERAL(&tcg_ctx->ops, begin, end, link);
254*38b47b19SEmilio G. Cota     return ret;
255*38b47b19SEmilio G. Cota }
256*38b47b19SEmilio G. Cota 
257*38b47b19SEmilio G. Cota /* remove all ops until (and including) plugin_cb_end */
258*38b47b19SEmilio G. Cota static TCGOp *rm_ops(TCGOp *op)
259*38b47b19SEmilio G. Cota {
260*38b47b19SEmilio G. Cota     TCGOp *end_op = find_op(op, INDEX_op_plugin_cb_end);
261*38b47b19SEmilio G. Cota 
262*38b47b19SEmilio G. Cota     tcg_debug_assert(end_op);
263*38b47b19SEmilio G. Cota     return rm_ops_range(op, end_op);
264*38b47b19SEmilio G. Cota }
265*38b47b19SEmilio G. Cota 
266*38b47b19SEmilio G. Cota static TCGOp *copy_op_nocheck(TCGOp **begin_op, TCGOp *op)
267*38b47b19SEmilio G. Cota {
268*38b47b19SEmilio G. Cota     *begin_op = QTAILQ_NEXT(*begin_op, link);
269*38b47b19SEmilio G. Cota     tcg_debug_assert(*begin_op);
270*38b47b19SEmilio G. Cota     op = tcg_op_insert_after(tcg_ctx, op, (*begin_op)->opc);
271*38b47b19SEmilio G. Cota     memcpy(op->args, (*begin_op)->args, sizeof(op->args));
272*38b47b19SEmilio G. Cota     return op;
273*38b47b19SEmilio G. Cota }
274*38b47b19SEmilio G. Cota 
275*38b47b19SEmilio G. Cota static TCGOp *copy_op(TCGOp **begin_op, TCGOp *op, TCGOpcode opc)
276*38b47b19SEmilio G. Cota {
277*38b47b19SEmilio G. Cota     op = copy_op_nocheck(begin_op, op);
278*38b47b19SEmilio G. Cota     tcg_debug_assert((*begin_op)->opc == opc);
279*38b47b19SEmilio G. Cota     return op;
280*38b47b19SEmilio G. Cota }
281*38b47b19SEmilio G. Cota 
282*38b47b19SEmilio G. Cota static TCGOp *copy_extu_i32_i64(TCGOp **begin_op, TCGOp *op)
283*38b47b19SEmilio G. Cota {
284*38b47b19SEmilio G. Cota     if (TCG_TARGET_REG_BITS == 32) {
285*38b47b19SEmilio G. Cota         /* mov_i32 */
286*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_mov_i32);
287*38b47b19SEmilio G. Cota         /* movi_i32 */
288*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_movi_i32);
289*38b47b19SEmilio G. Cota     } else {
290*38b47b19SEmilio G. Cota         /* extu_i32_i64 */
291*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_extu_i32_i64);
292*38b47b19SEmilio G. Cota     }
293*38b47b19SEmilio G. Cota     return op;
294*38b47b19SEmilio G. Cota }
295*38b47b19SEmilio G. Cota 
296*38b47b19SEmilio G. Cota static TCGOp *copy_mov_i64(TCGOp **begin_op, TCGOp *op)
297*38b47b19SEmilio G. Cota {
298*38b47b19SEmilio G. Cota     if (TCG_TARGET_REG_BITS == 32) {
299*38b47b19SEmilio G. Cota         /* 2x mov_i32 */
300*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_mov_i32);
301*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_mov_i32);
302*38b47b19SEmilio G. Cota     } else {
303*38b47b19SEmilio G. Cota         /* mov_i64 */
304*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_mov_i64);
305*38b47b19SEmilio G. Cota     }
306*38b47b19SEmilio G. Cota     return op;
307*38b47b19SEmilio G. Cota }
308*38b47b19SEmilio G. Cota 
309*38b47b19SEmilio G. Cota static TCGOp *copy_movi_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
310*38b47b19SEmilio G. Cota {
311*38b47b19SEmilio G. Cota     if (TCG_TARGET_REG_BITS == 32) {
312*38b47b19SEmilio G. Cota         /* 2x movi_i32 */
313*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_movi_i32);
314*38b47b19SEmilio G. Cota         op->args[1] = v;
315*38b47b19SEmilio G. Cota 
316*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_movi_i32);
317*38b47b19SEmilio G. Cota         op->args[1] = v >> 32;
318*38b47b19SEmilio G. Cota     } else {
319*38b47b19SEmilio G. Cota         /* movi_i64 */
320*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_movi_i64);
321*38b47b19SEmilio G. Cota         op->args[1] = v;
322*38b47b19SEmilio G. Cota     }
323*38b47b19SEmilio G. Cota     return op;
324*38b47b19SEmilio G. Cota }
325*38b47b19SEmilio G. Cota 
326*38b47b19SEmilio G. Cota static TCGOp *copy_const_ptr(TCGOp **begin_op, TCGOp *op, void *ptr)
327*38b47b19SEmilio G. Cota {
328*38b47b19SEmilio G. Cota     if (UINTPTR_MAX == UINT32_MAX) {
329*38b47b19SEmilio G. Cota         /* movi_i32 */
330*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_movi_i32);
331*38b47b19SEmilio G. Cota         op->args[1] = (uintptr_t)ptr;
332*38b47b19SEmilio G. Cota     } else {
333*38b47b19SEmilio G. Cota         /* movi_i64 */
334*38b47b19SEmilio G. Cota         op = copy_movi_i64(begin_op, op, (uint64_t)(uintptr_t)ptr);
335*38b47b19SEmilio G. Cota     }
336*38b47b19SEmilio G. Cota     return op;
337*38b47b19SEmilio G. Cota }
338*38b47b19SEmilio G. Cota 
339*38b47b19SEmilio G. Cota static TCGOp *copy_const_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
340*38b47b19SEmilio G. Cota {
341*38b47b19SEmilio G. Cota     return copy_movi_i64(begin_op, op, v);
342*38b47b19SEmilio G. Cota }
343*38b47b19SEmilio G. Cota 
344*38b47b19SEmilio G. Cota static TCGOp *copy_extu_tl_i64(TCGOp **begin_op, TCGOp *op)
345*38b47b19SEmilio G. Cota {
346*38b47b19SEmilio G. Cota     if (TARGET_LONG_BITS == 32) {
347*38b47b19SEmilio G. Cota         /* extu_i32_i64 */
348*38b47b19SEmilio G. Cota         op = copy_extu_i32_i64(begin_op, op);
349*38b47b19SEmilio G. Cota     } else {
350*38b47b19SEmilio G. Cota         /* mov_i64 */
351*38b47b19SEmilio G. Cota         op = copy_mov_i64(begin_op, op);
352*38b47b19SEmilio G. Cota     }
353*38b47b19SEmilio G. Cota     return op;
354*38b47b19SEmilio G. Cota }
355*38b47b19SEmilio G. Cota 
356*38b47b19SEmilio G. Cota static TCGOp *copy_ld_i64(TCGOp **begin_op, TCGOp *op)
357*38b47b19SEmilio G. Cota {
358*38b47b19SEmilio G. Cota     if (TCG_TARGET_REG_BITS == 32) {
359*38b47b19SEmilio G. Cota         /* 2x ld_i32 */
360*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_ld_i32);
361*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_ld_i32);
362*38b47b19SEmilio G. Cota     } else {
363*38b47b19SEmilio G. Cota         /* ld_i64 */
364*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_ld_i64);
365*38b47b19SEmilio G. Cota     }
366*38b47b19SEmilio G. Cota     return op;
367*38b47b19SEmilio G. Cota }
368*38b47b19SEmilio G. Cota 
369*38b47b19SEmilio G. Cota static TCGOp *copy_st_i64(TCGOp **begin_op, TCGOp *op)
370*38b47b19SEmilio G. Cota {
371*38b47b19SEmilio G. Cota     if (TCG_TARGET_REG_BITS == 32) {
372*38b47b19SEmilio G. Cota         /* 2x st_i32 */
373*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_st_i32);
374*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_st_i32);
375*38b47b19SEmilio G. Cota     } else {
376*38b47b19SEmilio G. Cota         /* st_i64 */
377*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_st_i64);
378*38b47b19SEmilio G. Cota     }
379*38b47b19SEmilio G. Cota     return op;
380*38b47b19SEmilio G. Cota }
381*38b47b19SEmilio G. Cota 
382*38b47b19SEmilio G. Cota static TCGOp *copy_add_i64(TCGOp **begin_op, TCGOp *op)
383*38b47b19SEmilio G. Cota {
384*38b47b19SEmilio G. Cota     if (TCG_TARGET_REG_BITS == 32) {
385*38b47b19SEmilio G. Cota         /* all 32-bit backends must implement add2_i32 */
386*38b47b19SEmilio G. Cota         g_assert(TCG_TARGET_HAS_add2_i32);
387*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_add2_i32);
388*38b47b19SEmilio G. Cota     } else {
389*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_add_i64);
390*38b47b19SEmilio G. Cota     }
391*38b47b19SEmilio G. Cota     return op;
392*38b47b19SEmilio G. Cota }
393*38b47b19SEmilio G. Cota 
394*38b47b19SEmilio G. Cota static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op)
395*38b47b19SEmilio G. Cota {
396*38b47b19SEmilio G. Cota     if (UINTPTR_MAX == UINT32_MAX) {
397*38b47b19SEmilio G. Cota         /* st_i32 */
398*38b47b19SEmilio G. Cota         op = copy_op(begin_op, op, INDEX_op_st_i32);
399*38b47b19SEmilio G. Cota     } else {
400*38b47b19SEmilio G. Cota         /* st_i64 */
401*38b47b19SEmilio G. Cota         op = copy_st_i64(begin_op, op);
402*38b47b19SEmilio G. Cota     }
403*38b47b19SEmilio G. Cota     return op;
404*38b47b19SEmilio G. Cota }
405*38b47b19SEmilio G. Cota 
406*38b47b19SEmilio G. Cota static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *empty_func,
407*38b47b19SEmilio G. Cota                         void *func, unsigned tcg_flags, int *cb_idx)
408*38b47b19SEmilio G. Cota {
409*38b47b19SEmilio G. Cota     /* copy all ops until the call */
410*38b47b19SEmilio G. Cota     do {
411*38b47b19SEmilio G. Cota         op = copy_op_nocheck(begin_op, op);
412*38b47b19SEmilio G. Cota     } while (op->opc != INDEX_op_call);
413*38b47b19SEmilio G. Cota 
414*38b47b19SEmilio G. Cota     /* fill in the op call */
415*38b47b19SEmilio G. Cota     op->param1 = (*begin_op)->param1;
416*38b47b19SEmilio G. Cota     op->param2 = (*begin_op)->param2;
417*38b47b19SEmilio G. Cota     tcg_debug_assert(op->life == 0);
418*38b47b19SEmilio G. Cota     if (*cb_idx == -1) {
419*38b47b19SEmilio G. Cota         int i;
420*38b47b19SEmilio G. Cota 
421*38b47b19SEmilio G. Cota         /*
422*38b47b19SEmilio G. Cota          * Instead of working out the position of the callback in args[], just
423*38b47b19SEmilio G. Cota          * look for @empty_func, since it should be a unique pointer.
424*38b47b19SEmilio G. Cota          */
425*38b47b19SEmilio G. Cota         for (i = 0; i < MAX_OPC_PARAM_ARGS; i++) {
426*38b47b19SEmilio G. Cota             if ((uintptr_t)(*begin_op)->args[i] == (uintptr_t)empty_func) {
427*38b47b19SEmilio G. Cota                 *cb_idx = i;
428*38b47b19SEmilio G. Cota                 break;
429*38b47b19SEmilio G. Cota             }
430*38b47b19SEmilio G. Cota         }
431*38b47b19SEmilio G. Cota         tcg_debug_assert(i < MAX_OPC_PARAM_ARGS);
432*38b47b19SEmilio G. Cota     }
433*38b47b19SEmilio G. Cota     op->args[*cb_idx] = (uintptr_t)func;
434*38b47b19SEmilio G. Cota     op->args[*cb_idx + 1] = tcg_flags;
435*38b47b19SEmilio G. Cota 
436*38b47b19SEmilio G. Cota     return op;
437*38b47b19SEmilio G. Cota }
438*38b47b19SEmilio G. Cota 
439*38b47b19SEmilio G. Cota static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
440*38b47b19SEmilio G. Cota                               TCGOp *begin_op, TCGOp *op, int *cb_idx)
441*38b47b19SEmilio G. Cota {
442*38b47b19SEmilio G. Cota     /* const_ptr */
443*38b47b19SEmilio G. Cota     op = copy_const_ptr(&begin_op, op, cb->userp);
444*38b47b19SEmilio G. Cota 
445*38b47b19SEmilio G. Cota     /* copy the ld_i32, but note that we only have to copy it once */
446*38b47b19SEmilio G. Cota     begin_op = QTAILQ_NEXT(begin_op, link);
447*38b47b19SEmilio G. Cota     tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
448*38b47b19SEmilio G. Cota     if (*cb_idx == -1) {
449*38b47b19SEmilio G. Cota         op = tcg_op_insert_after(tcg_ctx, op, INDEX_op_ld_i32);
450*38b47b19SEmilio G. Cota         memcpy(op->args, begin_op->args, sizeof(op->args));
451*38b47b19SEmilio G. Cota     }
452*38b47b19SEmilio G. Cota 
453*38b47b19SEmilio G. Cota     /* call */
454*38b47b19SEmilio G. Cota     op = copy_call(&begin_op, op, HELPER(plugin_vcpu_udata_cb),
455*38b47b19SEmilio G. Cota                    cb->f.vcpu_udata, cb->tcg_flags, cb_idx);
456*38b47b19SEmilio G. Cota 
457*38b47b19SEmilio G. Cota     return op;
458*38b47b19SEmilio G. Cota }
459*38b47b19SEmilio G. Cota 
460*38b47b19SEmilio G. Cota static TCGOp *append_inline_cb(const struct qemu_plugin_dyn_cb *cb,
461*38b47b19SEmilio G. Cota                                TCGOp *begin_op, TCGOp *op,
462*38b47b19SEmilio G. Cota                                int *unused)
463*38b47b19SEmilio G. Cota {
464*38b47b19SEmilio G. Cota     /* const_ptr */
465*38b47b19SEmilio G. Cota     op = copy_const_ptr(&begin_op, op, cb->userp);
466*38b47b19SEmilio G. Cota 
467*38b47b19SEmilio G. Cota     /* ld_i64 */
468*38b47b19SEmilio G. Cota     op = copy_ld_i64(&begin_op, op);
469*38b47b19SEmilio G. Cota 
470*38b47b19SEmilio G. Cota     /* const_i64 */
471*38b47b19SEmilio G. Cota     op = copy_const_i64(&begin_op, op, cb->inline_insn.imm);
472*38b47b19SEmilio G. Cota 
473*38b47b19SEmilio G. Cota     /* add_i64 */
474*38b47b19SEmilio G. Cota     op = copy_add_i64(&begin_op, op);
475*38b47b19SEmilio G. Cota 
476*38b47b19SEmilio G. Cota     /* st_i64 */
477*38b47b19SEmilio G. Cota     op = copy_st_i64(&begin_op, op);
478*38b47b19SEmilio G. Cota 
479*38b47b19SEmilio G. Cota     return op;
480*38b47b19SEmilio G. Cota }
481*38b47b19SEmilio G. Cota 
482*38b47b19SEmilio G. Cota static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
483*38b47b19SEmilio G. Cota                             TCGOp *begin_op, TCGOp *op, int *cb_idx)
484*38b47b19SEmilio G. Cota {
485*38b47b19SEmilio G. Cota     enum plugin_gen_cb type = begin_op->args[1];
486*38b47b19SEmilio G. Cota 
487*38b47b19SEmilio G. Cota     tcg_debug_assert(type == PLUGIN_GEN_CB_MEM);
488*38b47b19SEmilio G. Cota 
489*38b47b19SEmilio G. Cota     /* const_i32 == movi_i32 ("info", so it remains as is) */
490*38b47b19SEmilio G. Cota     op = copy_op(&begin_op, op, INDEX_op_movi_i32);
491*38b47b19SEmilio G. Cota 
492*38b47b19SEmilio G. Cota     /* const_ptr */
493*38b47b19SEmilio G. Cota     op = copy_const_ptr(&begin_op, op, cb->userp);
494*38b47b19SEmilio G. Cota 
495*38b47b19SEmilio G. Cota     /* copy the ld_i32, but note that we only have to copy it once */
496*38b47b19SEmilio G. Cota     begin_op = QTAILQ_NEXT(begin_op, link);
497*38b47b19SEmilio G. Cota     tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
498*38b47b19SEmilio G. Cota     if (*cb_idx == -1) {
499*38b47b19SEmilio G. Cota         op = tcg_op_insert_after(tcg_ctx, op, INDEX_op_ld_i32);
500*38b47b19SEmilio G. Cota         memcpy(op->args, begin_op->args, sizeof(op->args));
501*38b47b19SEmilio G. Cota     }
502*38b47b19SEmilio G. Cota 
503*38b47b19SEmilio G. Cota     /* extu_tl_i64 */
504*38b47b19SEmilio G. Cota     op = copy_extu_tl_i64(&begin_op, op);
505*38b47b19SEmilio G. Cota 
506*38b47b19SEmilio G. Cota     if (type == PLUGIN_GEN_CB_MEM) {
507*38b47b19SEmilio G. Cota         /* call */
508*38b47b19SEmilio G. Cota         op = copy_call(&begin_op, op, HELPER(plugin_vcpu_mem_cb),
509*38b47b19SEmilio G. Cota                        cb->f.vcpu_udata, cb->tcg_flags, cb_idx);
510*38b47b19SEmilio G. Cota     }
511*38b47b19SEmilio G. Cota 
512*38b47b19SEmilio G. Cota     return op;
513*38b47b19SEmilio G. Cota }
514*38b47b19SEmilio G. Cota 
515*38b47b19SEmilio G. Cota typedef TCGOp *(*inject_fn)(const struct qemu_plugin_dyn_cb *cb,
516*38b47b19SEmilio G. Cota                             TCGOp *begin_op, TCGOp *op, int *intp);
517*38b47b19SEmilio G. Cota typedef bool (*op_ok_fn)(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb);
518*38b47b19SEmilio G. Cota 
519*38b47b19SEmilio G. Cota static bool op_ok(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
520*38b47b19SEmilio G. Cota {
521*38b47b19SEmilio G. Cota     return true;
522*38b47b19SEmilio G. Cota }
523*38b47b19SEmilio G. Cota 
524*38b47b19SEmilio G. Cota static bool op_rw(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
525*38b47b19SEmilio G. Cota {
526*38b47b19SEmilio G. Cota     int w;
527*38b47b19SEmilio G. Cota 
528*38b47b19SEmilio G. Cota     w = op->args[2];
529*38b47b19SEmilio G. Cota     return !!(cb->rw & (w + 1));
530*38b47b19SEmilio G. Cota }
531*38b47b19SEmilio G. Cota 
532*38b47b19SEmilio G. Cota static inline
533*38b47b19SEmilio G. Cota void inject_cb_type(const GArray *cbs, TCGOp *begin_op, inject_fn inject,
534*38b47b19SEmilio G. Cota                     op_ok_fn ok)
535*38b47b19SEmilio G. Cota {
536*38b47b19SEmilio G. Cota     TCGOp *end_op;
537*38b47b19SEmilio G. Cota     TCGOp *op;
538*38b47b19SEmilio G. Cota     int cb_idx = -1;
539*38b47b19SEmilio G. Cota     int i;
540*38b47b19SEmilio G. Cota 
541*38b47b19SEmilio G. Cota     if (!cbs || cbs->len == 0) {
542*38b47b19SEmilio G. Cota         rm_ops(begin_op);
543*38b47b19SEmilio G. Cota         return;
544*38b47b19SEmilio G. Cota     }
545*38b47b19SEmilio G. Cota 
546*38b47b19SEmilio G. Cota     end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
547*38b47b19SEmilio G. Cota     tcg_debug_assert(end_op);
548*38b47b19SEmilio G. Cota 
549*38b47b19SEmilio G. Cota     op = end_op;
550*38b47b19SEmilio G. Cota     for (i = 0; i < cbs->len; i++) {
551*38b47b19SEmilio G. Cota         struct qemu_plugin_dyn_cb *cb =
552*38b47b19SEmilio G. Cota             &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
553*38b47b19SEmilio G. Cota 
554*38b47b19SEmilio G. Cota         if (!ok(begin_op, cb)) {
555*38b47b19SEmilio G. Cota             continue;
556*38b47b19SEmilio G. Cota         }
557*38b47b19SEmilio G. Cota         op = inject(cb, begin_op, op, &cb_idx);
558*38b47b19SEmilio G. Cota     }
559*38b47b19SEmilio G. Cota     rm_ops_range(begin_op, end_op);
560*38b47b19SEmilio G. Cota }
561*38b47b19SEmilio G. Cota 
562*38b47b19SEmilio G. Cota static void
563*38b47b19SEmilio G. Cota inject_udata_cb(const GArray *cbs, TCGOp *begin_op)
564*38b47b19SEmilio G. Cota {
565*38b47b19SEmilio G. Cota     inject_cb_type(cbs, begin_op, append_udata_cb, op_ok);
566*38b47b19SEmilio G. Cota }
567*38b47b19SEmilio G. Cota 
568*38b47b19SEmilio G. Cota static void
569*38b47b19SEmilio G. Cota inject_inline_cb(const GArray *cbs, TCGOp *begin_op, op_ok_fn ok)
570*38b47b19SEmilio G. Cota {
571*38b47b19SEmilio G. Cota     inject_cb_type(cbs, begin_op, append_inline_cb, ok);
572*38b47b19SEmilio G. Cota }
573*38b47b19SEmilio G. Cota 
574*38b47b19SEmilio G. Cota static void
575*38b47b19SEmilio G. Cota inject_mem_cb(const GArray *cbs, TCGOp *begin_op)
576*38b47b19SEmilio G. Cota {
577*38b47b19SEmilio G. Cota     inject_cb_type(cbs, begin_op, append_mem_cb, op_rw);
578*38b47b19SEmilio G. Cota }
579*38b47b19SEmilio G. Cota 
580*38b47b19SEmilio G. Cota /* we could change the ops in place, but we can reuse more code by copying */
581*38b47b19SEmilio G. Cota static void inject_mem_helper(TCGOp *begin_op, GArray *arr)
582*38b47b19SEmilio G. Cota {
583*38b47b19SEmilio G. Cota     TCGOp *orig_op = begin_op;
584*38b47b19SEmilio G. Cota     TCGOp *end_op;
585*38b47b19SEmilio G. Cota     TCGOp *op;
586*38b47b19SEmilio G. Cota 
587*38b47b19SEmilio G. Cota     end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
588*38b47b19SEmilio G. Cota     tcg_debug_assert(end_op);
589*38b47b19SEmilio G. Cota 
590*38b47b19SEmilio G. Cota     /* const ptr */
591*38b47b19SEmilio G. Cota     op = copy_const_ptr(&begin_op, end_op, arr);
592*38b47b19SEmilio G. Cota 
593*38b47b19SEmilio G. Cota     /* st_ptr */
594*38b47b19SEmilio G. Cota     op = copy_st_ptr(&begin_op, op);
595*38b47b19SEmilio G. Cota 
596*38b47b19SEmilio G. Cota     rm_ops_range(orig_op, end_op);
597*38b47b19SEmilio G. Cota }
598*38b47b19SEmilio G. Cota 
599*38b47b19SEmilio G. Cota /*
600*38b47b19SEmilio G. Cota  * Tracking memory accesses performed from helpers requires extra work.
601*38b47b19SEmilio G. Cota  * If an instruction is emulated with helpers, we do two things:
602*38b47b19SEmilio G. Cota  * (1) copy the CB descriptors, and keep track of it so that they can be
603*38b47b19SEmilio G. Cota  * freed later on, and (2) point CPUState.plugin_mem_cbs to the descriptors, so
604*38b47b19SEmilio G. Cota  * that we can read them at run-time (i.e. when the helper executes).
605*38b47b19SEmilio G. Cota  * This run-time access is performed from qemu_plugin_vcpu_mem_cb.
606*38b47b19SEmilio G. Cota  *
607*38b47b19SEmilio G. Cota  * Note that plugin_gen_disable_mem_helpers undoes (2). Since it
608*38b47b19SEmilio G. Cota  * is possible that the code we generate after the instruction is
609*38b47b19SEmilio G. Cota  * dead, we also add checks before generating tb_exit etc.
610*38b47b19SEmilio G. Cota  */
611*38b47b19SEmilio G. Cota static void inject_mem_enable_helper(struct qemu_plugin_insn *plugin_insn,
612*38b47b19SEmilio G. Cota                                      TCGOp *begin_op)
613*38b47b19SEmilio G. Cota {
614*38b47b19SEmilio G. Cota     GArray *cbs[2];
615*38b47b19SEmilio G. Cota     GArray *arr;
616*38b47b19SEmilio G. Cota     size_t n_cbs, i;
617*38b47b19SEmilio G. Cota 
618*38b47b19SEmilio G. Cota     cbs[0] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
619*38b47b19SEmilio G. Cota     cbs[1] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
620*38b47b19SEmilio G. Cota 
621*38b47b19SEmilio G. Cota     n_cbs = 0;
622*38b47b19SEmilio G. Cota     for (i = 0; i < ARRAY_SIZE(cbs); i++) {
623*38b47b19SEmilio G. Cota         n_cbs += cbs[i]->len;
624*38b47b19SEmilio G. Cota     }
625*38b47b19SEmilio G. Cota 
626*38b47b19SEmilio G. Cota     plugin_insn->mem_helper = plugin_insn->calls_helpers && n_cbs;
627*38b47b19SEmilio G. Cota     if (likely(!plugin_insn->mem_helper)) {
628*38b47b19SEmilio G. Cota         rm_ops(begin_op);
629*38b47b19SEmilio G. Cota         return;
630*38b47b19SEmilio G. Cota     }
631*38b47b19SEmilio G. Cota 
632*38b47b19SEmilio G. Cota     arr = g_array_sized_new(false, false,
633*38b47b19SEmilio G. Cota                             sizeof(struct qemu_plugin_dyn_cb), n_cbs);
634*38b47b19SEmilio G. Cota 
635*38b47b19SEmilio G. Cota     for (i = 0; i < ARRAY_SIZE(cbs); i++) {
636*38b47b19SEmilio G. Cota         g_array_append_vals(arr, cbs[i]->data, cbs[i]->len);
637*38b47b19SEmilio G. Cota     }
638*38b47b19SEmilio G. Cota 
639*38b47b19SEmilio G. Cota     qemu_plugin_add_dyn_cb_arr(arr);
640*38b47b19SEmilio G. Cota     inject_mem_helper(begin_op, arr);
641*38b47b19SEmilio G. Cota }
642*38b47b19SEmilio G. Cota 
643*38b47b19SEmilio G. Cota static void inject_mem_disable_helper(struct qemu_plugin_insn *plugin_insn,
644*38b47b19SEmilio G. Cota                                       TCGOp *begin_op)
645*38b47b19SEmilio G. Cota {
646*38b47b19SEmilio G. Cota     if (likely(!plugin_insn->mem_helper)) {
647*38b47b19SEmilio G. Cota         rm_ops(begin_op);
648*38b47b19SEmilio G. Cota         return;
649*38b47b19SEmilio G. Cota     }
650*38b47b19SEmilio G. Cota     inject_mem_helper(begin_op, NULL);
651*38b47b19SEmilio G. Cota }
652*38b47b19SEmilio G. Cota 
653*38b47b19SEmilio G. Cota /* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
654*38b47b19SEmilio G. Cota void plugin_gen_disable_mem_helpers(void)
655*38b47b19SEmilio G. Cota {
656*38b47b19SEmilio G. Cota     TCGv_ptr ptr;
657*38b47b19SEmilio G. Cota 
658*38b47b19SEmilio G. Cota     if (likely(tcg_ctx->plugin_insn == NULL ||
659*38b47b19SEmilio G. Cota                !tcg_ctx->plugin_insn->mem_helper)) {
660*38b47b19SEmilio G. Cota         return;
661*38b47b19SEmilio G. Cota     }
662*38b47b19SEmilio G. Cota     ptr = tcg_const_ptr(NULL);
663*38b47b19SEmilio G. Cota     tcg_gen_st_ptr(ptr, cpu_env, offsetof(CPUState, plugin_mem_cbs) -
664*38b47b19SEmilio G. Cota                                  offsetof(ArchCPU, env));
665*38b47b19SEmilio G. Cota     tcg_temp_free_ptr(ptr);
666*38b47b19SEmilio G. Cota     tcg_ctx->plugin_insn->mem_helper = false;
667*38b47b19SEmilio G. Cota }
668*38b47b19SEmilio G. Cota 
669*38b47b19SEmilio G. Cota static void plugin_gen_tb_udata(const struct qemu_plugin_tb *ptb,
670*38b47b19SEmilio G. Cota                                 TCGOp *begin_op)
671*38b47b19SEmilio G. Cota {
672*38b47b19SEmilio G. Cota     inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR], begin_op);
673*38b47b19SEmilio G. Cota }
674*38b47b19SEmilio G. Cota 
675*38b47b19SEmilio G. Cota static void plugin_gen_tb_inline(const struct qemu_plugin_tb *ptb,
676*38b47b19SEmilio G. Cota                                  TCGOp *begin_op)
677*38b47b19SEmilio G. Cota {
678*38b47b19SEmilio G. Cota     inject_inline_cb(ptb->cbs[PLUGIN_CB_INLINE], begin_op, op_ok);
679*38b47b19SEmilio G. Cota }
680*38b47b19SEmilio G. Cota 
681*38b47b19SEmilio G. Cota static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
682*38b47b19SEmilio G. Cota                                   TCGOp *begin_op, int insn_idx)
683*38b47b19SEmilio G. Cota {
684*38b47b19SEmilio G. Cota     struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
685*38b47b19SEmilio G. Cota 
686*38b47b19SEmilio G. Cota     inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], begin_op);
687*38b47b19SEmilio G. Cota }
688*38b47b19SEmilio G. Cota 
689*38b47b19SEmilio G. Cota static void plugin_gen_insn_inline(const struct qemu_plugin_tb *ptb,
690*38b47b19SEmilio G. Cota                                    TCGOp *begin_op, int insn_idx)
691*38b47b19SEmilio G. Cota {
692*38b47b19SEmilio G. Cota     struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
693*38b47b19SEmilio G. Cota     inject_inline_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
694*38b47b19SEmilio G. Cota                      begin_op, op_ok);
695*38b47b19SEmilio G. Cota }
696*38b47b19SEmilio G. Cota 
697*38b47b19SEmilio G. Cota static void plugin_gen_mem_regular(const struct qemu_plugin_tb *ptb,
698*38b47b19SEmilio G. Cota                                    TCGOp *begin_op, int insn_idx)
699*38b47b19SEmilio G. Cota {
700*38b47b19SEmilio G. Cota     struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
701*38b47b19SEmilio G. Cota     inject_mem_cb(insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR], begin_op);
702*38b47b19SEmilio G. Cota }
703*38b47b19SEmilio G. Cota 
704*38b47b19SEmilio G. Cota static void plugin_gen_mem_inline(const struct qemu_plugin_tb *ptb,
705*38b47b19SEmilio G. Cota                                   TCGOp *begin_op, int insn_idx)
706*38b47b19SEmilio G. Cota {
707*38b47b19SEmilio G. Cota     const GArray *cbs;
708*38b47b19SEmilio G. Cota     struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
709*38b47b19SEmilio G. Cota 
710*38b47b19SEmilio G. Cota     cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
711*38b47b19SEmilio G. Cota     inject_inline_cb(cbs, begin_op, op_rw);
712*38b47b19SEmilio G. Cota }
713*38b47b19SEmilio G. Cota 
714*38b47b19SEmilio G. Cota static void plugin_gen_enable_mem_helper(const struct qemu_plugin_tb *ptb,
715*38b47b19SEmilio G. Cota                                          TCGOp *begin_op, int insn_idx)
716*38b47b19SEmilio G. Cota {
717*38b47b19SEmilio G. Cota     struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
718*38b47b19SEmilio G. Cota     inject_mem_enable_helper(insn, begin_op);
719*38b47b19SEmilio G. Cota }
720*38b47b19SEmilio G. Cota 
721*38b47b19SEmilio G. Cota static void plugin_gen_disable_mem_helper(const struct qemu_plugin_tb *ptb,
722*38b47b19SEmilio G. Cota                                           TCGOp *begin_op, int insn_idx)
723*38b47b19SEmilio G. Cota {
724*38b47b19SEmilio G. Cota     struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
725*38b47b19SEmilio G. Cota     inject_mem_disable_helper(insn, begin_op);
726*38b47b19SEmilio G. Cota }
727*38b47b19SEmilio G. Cota 
728*38b47b19SEmilio G. Cota static void plugin_inject_cb(const struct qemu_plugin_tb *ptb, TCGOp *begin_op,
729*38b47b19SEmilio G. Cota                              int insn_idx)
730*38b47b19SEmilio G. Cota {
731*38b47b19SEmilio G. Cota     enum plugin_gen_from from = begin_op->args[0];
732*38b47b19SEmilio G. Cota     enum plugin_gen_cb type = begin_op->args[1];
733*38b47b19SEmilio G. Cota 
734*38b47b19SEmilio G. Cota     switch (from) {
735*38b47b19SEmilio G. Cota     case PLUGIN_GEN_FROM_TB:
736*38b47b19SEmilio G. Cota         switch (type) {
737*38b47b19SEmilio G. Cota         case PLUGIN_GEN_CB_UDATA:
738*38b47b19SEmilio G. Cota             plugin_gen_tb_udata(ptb, begin_op);
739*38b47b19SEmilio G. Cota             return;
740*38b47b19SEmilio G. Cota         case PLUGIN_GEN_CB_INLINE:
741*38b47b19SEmilio G. Cota             plugin_gen_tb_inline(ptb, begin_op);
742*38b47b19SEmilio G. Cota             return;
743*38b47b19SEmilio G. Cota         default:
744*38b47b19SEmilio G. Cota             g_assert_not_reached();
745*38b47b19SEmilio G. Cota         }
746*38b47b19SEmilio G. Cota     case PLUGIN_GEN_FROM_INSN:
747*38b47b19SEmilio G. Cota         switch (type) {
748*38b47b19SEmilio G. Cota         case PLUGIN_GEN_CB_UDATA:
749*38b47b19SEmilio G. Cota             plugin_gen_insn_udata(ptb, begin_op, insn_idx);
750*38b47b19SEmilio G. Cota             return;
751*38b47b19SEmilio G. Cota         case PLUGIN_GEN_CB_INLINE:
752*38b47b19SEmilio G. Cota             plugin_gen_insn_inline(ptb, begin_op, insn_idx);
753*38b47b19SEmilio G. Cota             return;
754*38b47b19SEmilio G. Cota         case PLUGIN_GEN_ENABLE_MEM_HELPER:
755*38b47b19SEmilio G. Cota             plugin_gen_enable_mem_helper(ptb, begin_op, insn_idx);
756*38b47b19SEmilio G. Cota             return;
757*38b47b19SEmilio G. Cota         default:
758*38b47b19SEmilio G. Cota             g_assert_not_reached();
759*38b47b19SEmilio G. Cota         }
760*38b47b19SEmilio G. Cota     case PLUGIN_GEN_FROM_MEM:
761*38b47b19SEmilio G. Cota         switch (type) {
762*38b47b19SEmilio G. Cota         case PLUGIN_GEN_CB_MEM:
763*38b47b19SEmilio G. Cota             plugin_gen_mem_regular(ptb, begin_op, insn_idx);
764*38b47b19SEmilio G. Cota             return;
765*38b47b19SEmilio G. Cota         case PLUGIN_GEN_CB_INLINE:
766*38b47b19SEmilio G. Cota             plugin_gen_mem_inline(ptb, begin_op, insn_idx);
767*38b47b19SEmilio G. Cota             return;
768*38b47b19SEmilio G. Cota         default:
769*38b47b19SEmilio G. Cota             g_assert_not_reached();
770*38b47b19SEmilio G. Cota         }
771*38b47b19SEmilio G. Cota     case PLUGIN_GEN_AFTER_INSN:
772*38b47b19SEmilio G. Cota         switch (type) {
773*38b47b19SEmilio G. Cota         case PLUGIN_GEN_DISABLE_MEM_HELPER:
774*38b47b19SEmilio G. Cota             plugin_gen_disable_mem_helper(ptb, begin_op, insn_idx);
775*38b47b19SEmilio G. Cota             return;
776*38b47b19SEmilio G. Cota         default:
777*38b47b19SEmilio G. Cota             g_assert_not_reached();
778*38b47b19SEmilio G. Cota         }
779*38b47b19SEmilio G. Cota     default:
780*38b47b19SEmilio G. Cota         g_assert_not_reached();
781*38b47b19SEmilio G. Cota     }
782*38b47b19SEmilio G. Cota }
783*38b47b19SEmilio G. Cota 
784*38b47b19SEmilio G. Cota /* #define DEBUG_PLUGIN_GEN_OPS */
785*38b47b19SEmilio G. Cota static void pr_ops(void)
786*38b47b19SEmilio G. Cota {
787*38b47b19SEmilio G. Cota #ifdef DEBUG_PLUGIN_GEN_OPS
788*38b47b19SEmilio G. Cota     TCGOp *op;
789*38b47b19SEmilio G. Cota     int i = 0;
790*38b47b19SEmilio G. Cota 
791*38b47b19SEmilio G. Cota     QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
792*38b47b19SEmilio G. Cota         const char *name = "";
793*38b47b19SEmilio G. Cota         const char *type = "";
794*38b47b19SEmilio G. Cota 
795*38b47b19SEmilio G. Cota         if (op->opc == INDEX_op_plugin_cb_start) {
796*38b47b19SEmilio G. Cota             switch (op->args[0]) {
797*38b47b19SEmilio G. Cota             case PLUGIN_GEN_FROM_TB:
798*38b47b19SEmilio G. Cota                 name = "tb";
799*38b47b19SEmilio G. Cota                 break;
800*38b47b19SEmilio G. Cota             case PLUGIN_GEN_FROM_INSN:
801*38b47b19SEmilio G. Cota                 name = "insn";
802*38b47b19SEmilio G. Cota                 break;
803*38b47b19SEmilio G. Cota             case PLUGIN_GEN_FROM_MEM:
804*38b47b19SEmilio G. Cota                 name = "mem";
805*38b47b19SEmilio G. Cota                 break;
806*38b47b19SEmilio G. Cota             case PLUGIN_GEN_AFTER_INSN:
807*38b47b19SEmilio G. Cota                 name = "after insn";
808*38b47b19SEmilio G. Cota                 break;
809*38b47b19SEmilio G. Cota             default:
810*38b47b19SEmilio G. Cota                 break;
811*38b47b19SEmilio G. Cota             }
812*38b47b19SEmilio G. Cota             switch (op->args[1]) {
813*38b47b19SEmilio G. Cota             case PLUGIN_GEN_CB_UDATA:
814*38b47b19SEmilio G. Cota                 type = "udata";
815*38b47b19SEmilio G. Cota                 break;
816*38b47b19SEmilio G. Cota             case PLUGIN_GEN_CB_INLINE:
817*38b47b19SEmilio G. Cota                 type = "inline";
818*38b47b19SEmilio G. Cota                 break;
819*38b47b19SEmilio G. Cota             case PLUGIN_GEN_CB_MEM:
820*38b47b19SEmilio G. Cota                 type = "mem";
821*38b47b19SEmilio G. Cota                 break;
822*38b47b19SEmilio G. Cota             case PLUGIN_GEN_ENABLE_MEM_HELPER:
823*38b47b19SEmilio G. Cota                 type = "enable mem helper";
824*38b47b19SEmilio G. Cota                 break;
825*38b47b19SEmilio G. Cota             case PLUGIN_GEN_DISABLE_MEM_HELPER:
826*38b47b19SEmilio G. Cota                 type = "disable mem helper";
827*38b47b19SEmilio G. Cota                 break;
828*38b47b19SEmilio G. Cota             default:
829*38b47b19SEmilio G. Cota                 break;
830*38b47b19SEmilio G. Cota             }
831*38b47b19SEmilio G. Cota         }
832*38b47b19SEmilio G. Cota         printf("op[%2i]: %s %s %s\n", i, tcg_op_defs[op->opc].name, name, type);
833*38b47b19SEmilio G. Cota         i++;
834*38b47b19SEmilio G. Cota     }
835*38b47b19SEmilio G. Cota #endif
836*38b47b19SEmilio G. Cota }
837*38b47b19SEmilio G. Cota 
838*38b47b19SEmilio G. Cota static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb)
839*38b47b19SEmilio G. Cota {
840*38b47b19SEmilio G. Cota     TCGOp *op;
841*38b47b19SEmilio G. Cota     int insn_idx;
842*38b47b19SEmilio G. Cota 
843*38b47b19SEmilio G. Cota     pr_ops();
844*38b47b19SEmilio G. Cota     insn_idx = -1;
845*38b47b19SEmilio G. Cota     QSIMPLEQ_FOREACH(op, &tcg_ctx->plugin_ops, plugin_link) {
846*38b47b19SEmilio G. Cota         enum plugin_gen_from from = op->args[0];
847*38b47b19SEmilio G. Cota         enum plugin_gen_cb type = op->args[1];
848*38b47b19SEmilio G. Cota 
849*38b47b19SEmilio G. Cota         tcg_debug_assert(op->opc == INDEX_op_plugin_cb_start);
850*38b47b19SEmilio G. Cota         /* ENABLE_MEM_HELPER is the first callback of an instruction */
851*38b47b19SEmilio G. Cota         if (from == PLUGIN_GEN_FROM_INSN &&
852*38b47b19SEmilio G. Cota             type == PLUGIN_GEN_ENABLE_MEM_HELPER) {
853*38b47b19SEmilio G. Cota             insn_idx++;
854*38b47b19SEmilio G. Cota         }
855*38b47b19SEmilio G. Cota         plugin_inject_cb(plugin_tb, op, insn_idx);
856*38b47b19SEmilio G. Cota     }
857*38b47b19SEmilio G. Cota     pr_ops();
858*38b47b19SEmilio G. Cota }
859*38b47b19SEmilio G. Cota 
860*38b47b19SEmilio G. Cota bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb)
861*38b47b19SEmilio G. Cota {
862*38b47b19SEmilio G. Cota     struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
863*38b47b19SEmilio G. Cota     bool ret = false;
864*38b47b19SEmilio G. Cota 
865*38b47b19SEmilio G. Cota     if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_mask)) {
866*38b47b19SEmilio G. Cota         ret = true;
867*38b47b19SEmilio G. Cota 
868*38b47b19SEmilio G. Cota         QSIMPLEQ_INIT(&tcg_ctx->plugin_ops);
869*38b47b19SEmilio G. Cota         ptb->vaddr = tb->pc;
870*38b47b19SEmilio G. Cota         ptb->vaddr2 = -1;
871*38b47b19SEmilio G. Cota         get_page_addr_code_hostp(cpu->env_ptr, tb->pc, &ptb->haddr1);
872*38b47b19SEmilio G. Cota         ptb->haddr2 = NULL;
873*38b47b19SEmilio G. Cota 
874*38b47b19SEmilio G. Cota         plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB);
875*38b47b19SEmilio G. Cota     }
876*38b47b19SEmilio G. Cota     return ret;
877*38b47b19SEmilio G. Cota }
878*38b47b19SEmilio G. Cota 
879*38b47b19SEmilio G. Cota void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
880*38b47b19SEmilio G. Cota {
881*38b47b19SEmilio G. Cota     struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
882*38b47b19SEmilio G. Cota     struct qemu_plugin_insn *pinsn;
883*38b47b19SEmilio G. Cota 
884*38b47b19SEmilio G. Cota     pinsn = qemu_plugin_tb_insn_get(ptb);
885*38b47b19SEmilio G. Cota     tcg_ctx->plugin_insn = pinsn;
886*38b47b19SEmilio G. Cota     pinsn->vaddr = db->pc_next;
887*38b47b19SEmilio G. Cota     plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
888*38b47b19SEmilio G. Cota 
889*38b47b19SEmilio G. Cota     /*
890*38b47b19SEmilio G. Cota      * Detect page crossing to get the new host address.
891*38b47b19SEmilio G. Cota      * Note that we skip this when haddr1 == NULL, e.g. when we're
892*38b47b19SEmilio G. Cota      * fetching instructions from a region not backed by RAM.
893*38b47b19SEmilio G. Cota      */
894*38b47b19SEmilio G. Cota     if (likely(ptb->haddr1 != NULL && ptb->vaddr2 == -1) &&
895*38b47b19SEmilio G. Cota         unlikely((db->pc_next & TARGET_PAGE_MASK) !=
896*38b47b19SEmilio G. Cota                  (db->pc_first & TARGET_PAGE_MASK))) {
897*38b47b19SEmilio G. Cota         get_page_addr_code_hostp(cpu->env_ptr, db->pc_next,
898*38b47b19SEmilio G. Cota                                  &ptb->haddr2);
899*38b47b19SEmilio G. Cota         ptb->vaddr2 = db->pc_next;
900*38b47b19SEmilio G. Cota     }
901*38b47b19SEmilio G. Cota     if (likely(ptb->vaddr2 == -1)) {
902*38b47b19SEmilio G. Cota         pinsn->haddr = ptb->haddr1 + pinsn->vaddr - ptb->vaddr;
903*38b47b19SEmilio G. Cota     } else {
904*38b47b19SEmilio G. Cota         pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2;
905*38b47b19SEmilio G. Cota     }
906*38b47b19SEmilio G. Cota }
907*38b47b19SEmilio G. Cota 
908*38b47b19SEmilio G. Cota void plugin_gen_insn_end(void)
909*38b47b19SEmilio G. Cota {
910*38b47b19SEmilio G. Cota     plugin_gen_empty_callback(PLUGIN_GEN_AFTER_INSN);
911*38b47b19SEmilio G. Cota }
912*38b47b19SEmilio G. Cota 
913*38b47b19SEmilio G. Cota void plugin_gen_tb_end(CPUState *cpu)
914*38b47b19SEmilio G. Cota {
915*38b47b19SEmilio G. Cota     struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
916*38b47b19SEmilio G. Cota     int i;
917*38b47b19SEmilio G. Cota 
918*38b47b19SEmilio G. Cota     /* collect instrumentation requests */
919*38b47b19SEmilio G. Cota     qemu_plugin_tb_trans_cb(cpu, ptb);
920*38b47b19SEmilio G. Cota 
921*38b47b19SEmilio G. Cota     /* inject the instrumentation at the appropriate places */
922*38b47b19SEmilio G. Cota     plugin_gen_inject(ptb);
923*38b47b19SEmilio G. Cota 
924*38b47b19SEmilio G. Cota     /* clean up */
925*38b47b19SEmilio G. Cota     for (i = 0; i < PLUGIN_N_CB_SUBTYPES; i++) {
926*38b47b19SEmilio G. Cota         if (ptb->cbs[i]) {
927*38b47b19SEmilio G. Cota             g_array_set_size(ptb->cbs[i], 0);
928*38b47b19SEmilio G. Cota         }
929*38b47b19SEmilio G. Cota     }
930*38b47b19SEmilio G. Cota     ptb->n = 0;
931*38b47b19SEmilio G. Cota     tcg_ctx->plugin_insn = NULL;
932*38b47b19SEmilio G. Cota }
933