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