aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2024-05-01 15:15:33 -0700
committerRichard Henderson <richard.henderson@linaro.org>2024-05-01 15:15:33 -0700
commit4977ce198d2390bff8c71ad5cb1a5f6aa24b56fb (patch)
tree9dfc27d7f9bc9ceba0cd24c95b320f408046125d
parent935da8c66e12796510cf2ab2978934c273999f3b (diff)
parent917d7f8d948d706e275c9f33169b9dd0149ded1e (diff)
downloadqemu-upstream-master.tar.gz
Merge tag 'pull-tcg-20240501' of https://gitlab.com/rth7680/qemu into stagingupstream-master
plugins: Rewrite plugin tcg expansion # -----BEGIN PGP SIGNATURE----- # # iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmYyUpkdHHJpY2hhcmQu # aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV98VAgAoTqIWPHtPJOS800G # TlFuQjkEzQCPSKAh6ZbotsAMvfNwBloPpdrUlFr/jT7mURjEl2B7UC/4LzdhuGeQ # U/xZt5rXsYvyfS3VwLf8pKBIscF7XjJ1rdfYMvBg9XaNp5VV0aEIk3+6P0uYtzXG # cREF0uCYfdK6uoiuifhqRAkgrNnamdwpPbbfvzDQI13wICW7SfR7dcd629clVZ1O # QvD1M4bpTWyhClbZzaoHqyPs+HQEM/AY0wOTfYZNbQBu6zFZXNDZCvYhIEWonPBO # AKe5KWUrQMwLJhRVejaSSZZDjMdcz3HLaGJppP89/WB+gpY09+LsiuqT7k5c12Bw # ueLEhw== # =mn63 # -----END PGP SIGNATURE----- # gpg: Signature made Wed 01 May 2024 07:32:57 AM PDT # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate] * tag 'pull-tcg-20240501' of https://gitlab.com/rth7680/qemu: plugins: Update the documentation block for plugin-gen.c plugins: Inline plugin_gen_empty_callback plugins: Merge qemu_plugin_tb_insn_get to plugin-gen.c plugins: Split out common cb expanders plugins: Replace pr_ops with a proper debug dump flag plugins: Introduce PLUGIN_CB_MEM_REGULAR plugins: Simplify callback queues tcg: Remove INDEX_op_plugin_cb_{start,end} tcg: Remove TCG_CALL_PLUGIN plugins: Remove plugin helpers plugins: Use emit_before_op for PLUGIN_GEN_FROM_MEM plugins: Use emit_before_op for PLUGIN_GEN_FROM_INSN plugins: Add PLUGIN_GEN_AFTER_TB plugins: Use emit_before_op for PLUGIN_GEN_FROM_TB plugins: Use emit_before_op for PLUGIN_GEN_AFTER_INSN plugins: Create TCGHelperInfo for all out-of-line callbacks plugins: Move function pointer in qemu_plugin_dyn_cb plugins: Zero new qemu_plugin_dyn_cb entries tcg: Pass function pointer to tcg_gen_call* tcg: Make tcg/helper-info.h self-contained Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--accel/tcg/plugin-gen.c991
-rw-r--r--accel/tcg/plugin-helpers.h5
-rw-r--r--include/exec/helper-gen-common.h4
-rw-r--r--include/exec/helper-gen.h.inc24
-rw-r--r--include/exec/helper-proto-common.h4
-rw-r--r--include/exec/plugin-gen.h4
-rw-r--r--include/qemu/log.h1
-rw-r--r--include/qemu/plugin.h67
-rw-r--r--include/tcg/helper-info.h3
-rw-r--r--include/tcg/tcg-op-common.h4
-rw-r--r--include/tcg/tcg-opc.h4
-rw-r--r--include/tcg/tcg.h26
-rw-r--r--plugins/api.c26
-rw-r--r--plugins/core.c61
-rw-r--r--tcg/tcg-op-ldst.c6
-rw-r--r--tcg/tcg-op.c8
-rw-r--r--tcg/tcg.c78
-rw-r--r--tcg/tci.c1
-rw-r--r--util/log.c4
19 files changed, 391 insertions, 930 deletions
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index cd78ef94a1..3db74ae9bf 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -14,36 +14,14 @@
* Injecting the desired instrumentation could be done with a second
* translation pass that combined the instrumentation requests, but that
* would be ugly and inefficient since we would decode the guest code twice.
- * Instead, during TB translation we add "empty" instrumentation calls for all
- * possible instrumentation events, and then once we collect the instrumentation
- * requests from plugins, we either "fill in" those empty events or remove them
- * if they have no requests.
- *
- * When "filling in" an event we first copy the empty callback's TCG ops. This
- * might seem unnecessary, but it is done to support an arbitrary number
- * of callbacks per event. Take for example a regular instruction callback.
- * We first generate a callback to an empty helper function. Then, if two
- * plugins register one callback each for this instruction, we make two copies
- * of the TCG ops generated for the empty callback, substituting the function
- * pointer that points to the empty helper function with the plugins' desired
- * callback functions. After that we remove the empty callback's ops.
- *
- * Note that the location in TCGOp.args[] of the pointer to a helper function
- * varies across different guest and host architectures. Instead of duplicating
- * the logic that figures this out, we rely on the fact that the empty
- * callbacks point to empty functions that are unique pointers in the program.
- * Thus, to find the right location we just have to look for a match in
- * TCGOp.args[]. This is the main reason why we first copy an empty callback's
- * TCG ops and then fill them in; regardless of whether we have one or many
- * callbacks for that event, the logic to add all of them is the same.
- *
- * When generating more than one callback per event, we make a small
- * optimization to avoid generating redundant operations. For instance, for the
- * second and all subsequent callbacks of an event, we do not need to reload the
- * CPU's index into a TCG temp, since the first callback did it already.
+ * Instead, during TB translation we add "plugin_cb" marker opcodes
+ * for all possible instrumentation events, and then once we collect the
+ * instrumentation requests from plugins, we generate code for those markers
+ * or remove them if they have no requests.
*/
#include "qemu/osdep.h"
#include "qemu/plugin.h"
+#include "qemu/log.h"
#include "cpu.h"
#include "tcg/tcg.h"
#include "tcg/tcg-temp-internal.h"
@@ -51,819 +29,278 @@
#include "exec/exec-all.h"
#include "exec/plugin-gen.h"
#include "exec/translator.h"
-#include "exec/helper-proto-common.h"
-
-#define HELPER_H "accel/tcg/plugin-helpers.h"
-#include "exec/helper-info.c.inc"
-#undef HELPER_H
-
-/*
- * plugin_cb_start TCG op args[]:
- * 0: enum plugin_gen_from
- * 1: enum plugin_gen_cb
- * 2: set to 1 for mem callback that is a write, 0 otherwise.
- */
enum plugin_gen_from {
PLUGIN_GEN_FROM_TB,
PLUGIN_GEN_FROM_INSN,
- PLUGIN_GEN_FROM_MEM,
PLUGIN_GEN_AFTER_INSN,
- PLUGIN_GEN_N_FROMS,
-};
-
-enum plugin_gen_cb {
- PLUGIN_GEN_CB_UDATA,
- PLUGIN_GEN_CB_UDATA_R,
- PLUGIN_GEN_CB_INLINE,
- PLUGIN_GEN_CB_MEM,
- PLUGIN_GEN_ENABLE_MEM_HELPER,
- PLUGIN_GEN_DISABLE_MEM_HELPER,
- PLUGIN_GEN_N_CBS,
+ PLUGIN_GEN_AFTER_TB,
};
-/*
- * These helpers are stubs that get dynamically switched out for calls
- * direct to the plugin if they are subscribed to.
- */
-void HELPER(plugin_vcpu_udata_cb_no_wg)(uint32_t cpu_index, void *udata)
-{ }
+/* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
+void plugin_gen_disable_mem_helpers(void)
+{
+ if (tcg_ctx->plugin_insn) {
+ tcg_gen_plugin_cb(PLUGIN_GEN_AFTER_TB);
+ }
+}
-void HELPER(plugin_vcpu_udata_cb_no_rwg)(uint32_t cpu_index, void *udata)
-{ }
+static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
+ struct qemu_plugin_insn *insn)
+{
+ GArray *arr;
+ size_t len;
-void HELPER(plugin_vcpu_mem_cb)(unsigned int vcpu_index,
- qemu_plugin_meminfo_t info, uint64_t vaddr,
- void *userdata)
-{ }
+ /*
+ * Tracking memory accesses performed from helpers requires extra work.
+ * If an instruction is emulated with helpers, we do two things:
+ * (1) copy the CB descriptors, and keep track of it so that they can be
+ * freed later on, and (2) point CPUState.plugin_mem_cbs to the
+ * descriptors, so that we can read them at run-time
+ * (i.e. when the helper executes).
+ * This run-time access is performed from qemu_plugin_vcpu_mem_cb.
+ *
+ * Note that plugin_gen_disable_mem_helpers undoes (2). Since it
+ * is possible that the code we generate after the instruction is
+ * dead, we also add checks before generating tb_exit etc.
+ */
+ if (!insn->calls_helpers) {
+ return;
+ }
-static void gen_empty_udata_cb(void (*gen_helper)(TCGv_i32, TCGv_ptr))
-{
- TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
- TCGv_ptr udata = tcg_temp_ebb_new_ptr();
+ if (!insn->mem_cbs || !insn->mem_cbs->len) {
+ insn->mem_helper = false;
+ return;
+ }
+ insn->mem_helper = true;
+ ptb->mem_helper = true;
- tcg_gen_movi_ptr(udata, 0);
- tcg_gen_ld_i32(cpu_index, tcg_env,
- -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
- gen_helper(cpu_index, udata);
+ /*
+ * TODO: It seems like we should be able to use ref/unref
+ * to avoid needing to actually copy this array.
+ * Alternately, perhaps we could allocate new memory adjacent
+ * to the TranslationBlock itself, so that we do not have to
+ * actively manage the lifetime after this.
+ */
+ len = insn->mem_cbs->len;
+ arr = g_array_sized_new(false, false,
+ sizeof(struct qemu_plugin_dyn_cb), len);
+ memcpy(arr->data, insn->mem_cbs->data,
+ len * sizeof(struct qemu_plugin_dyn_cb));
+ qemu_plugin_add_dyn_cb_arr(arr);
- tcg_temp_free_ptr(udata);
- tcg_temp_free_i32(cpu_index);
+ tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env,
+ offsetof(CPUState, plugin_mem_cbs) -
+ offsetof(ArchCPU, env));
}
-static void gen_empty_udata_cb_no_wg(void)
+static void gen_disable_mem_helper(void)
{
- gen_empty_udata_cb(gen_helper_plugin_vcpu_udata_cb_no_wg);
+ tcg_gen_st_ptr(tcg_constant_ptr(0), tcg_env,
+ offsetof(CPUState, plugin_mem_cbs) -
+ offsetof(ArchCPU, env));
}
-static void gen_empty_udata_cb_no_rwg(void)
+static void gen_udata_cb(struct qemu_plugin_dyn_cb *cb)
{
- gen_empty_udata_cb(gen_helper_plugin_vcpu_udata_cb_no_rwg);
+ TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
+
+ tcg_gen_ld_i32(cpu_index, tcg_env,
+ -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
+ tcg_gen_call2(cb->regular.f.vcpu_udata, cb->regular.info, NULL,
+ tcgv_i32_temp(cpu_index),
+ tcgv_ptr_temp(tcg_constant_ptr(cb->userp)));
+ tcg_temp_free_i32(cpu_index);
}
-/*
- * For now we only support addi_i64.
- * When we support more ops, we can generate one empty inline cb for each.
- */
-static void gen_empty_inline_cb(void)
+static void gen_inline_cb(struct qemu_plugin_dyn_cb *cb)
{
+ GArray *arr = cb->inline_insn.entry.score->data;
+ size_t offset = cb->inline_insn.entry.offset;
TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
- TCGv_ptr cpu_index_as_ptr = tcg_temp_ebb_new_ptr();
TCGv_i64 val = tcg_temp_ebb_new_i64();
TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
tcg_gen_ld_i32(cpu_index, tcg_env,
-offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
- /* second operand will be replaced by immediate value */
- tcg_gen_mul_i32(cpu_index, cpu_index, cpu_index);
- tcg_gen_ext_i32_ptr(cpu_index_as_ptr, cpu_index);
+ tcg_gen_muli_i32(cpu_index, cpu_index, g_array_get_element_size(arr));
+ tcg_gen_ext_i32_ptr(ptr, cpu_index);
+ tcg_temp_free_i32(cpu_index);
- tcg_gen_movi_ptr(ptr, 0);
- tcg_gen_add_ptr(ptr, ptr, cpu_index_as_ptr);
- tcg_gen_ld_i64(val, ptr, 0);
- /* second operand will be replaced by immediate value */
- tcg_gen_add_i64(val, val, val);
+ tcg_gen_addi_ptr(ptr, ptr, (intptr_t)arr->data);
+ tcg_gen_ld_i64(val, ptr, offset);
+ tcg_gen_addi_i64(val, val, cb->inline_insn.imm);
+ tcg_gen_st_i64(val, ptr, offset);
- tcg_gen_st_i64(val, ptr, 0);
- tcg_temp_free_ptr(ptr);
tcg_temp_free_i64(val);
- tcg_temp_free_ptr(cpu_index_as_ptr);
- tcg_temp_free_i32(cpu_index);
+ tcg_temp_free_ptr(ptr);
}
-static void gen_empty_mem_cb(TCGv_i64 addr, uint32_t info)
+static void gen_mem_cb(struct qemu_plugin_dyn_cb *cb,
+ qemu_plugin_meminfo_t meminfo, TCGv_i64 addr)
{
TCGv_i32 cpu_index = tcg_temp_ebb_new_i32();
- TCGv_i32 meminfo = tcg_temp_ebb_new_i32();
- TCGv_ptr udata = tcg_temp_ebb_new_ptr();
- tcg_gen_movi_i32(meminfo, info);
- tcg_gen_movi_ptr(udata, 0);
tcg_gen_ld_i32(cpu_index, tcg_env,
-offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
-
- gen_helper_plugin_vcpu_mem_cb(cpu_index, meminfo, addr, udata);
-
- tcg_temp_free_ptr(udata);
- tcg_temp_free_i32(meminfo);
+ tcg_gen_call4(cb->regular.f.vcpu_mem, cb->regular.info, NULL,
+ tcgv_i32_temp(cpu_index),
+ tcgv_i32_temp(tcg_constant_i32(meminfo)),
+ tcgv_i64_temp(addr),
+ tcgv_ptr_temp(tcg_constant_ptr(cb->userp)));
tcg_temp_free_i32(cpu_index);
}
-/*
- * Share the same function for enable/disable. When enabling, the NULL
- * pointer will be overwritten later.
- */
-static void gen_empty_mem_helper(void)
-{
- TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
-
- tcg_gen_movi_ptr(ptr, 0);
- tcg_gen_st_ptr(ptr, tcg_env, offsetof(CPUState, plugin_mem_cbs) -
- offsetof(ArchCPU, env));
- tcg_temp_free_ptr(ptr);
-}
-
-static void gen_plugin_cb_start(enum plugin_gen_from from,
- enum plugin_gen_cb type, unsigned wr)
-{
- tcg_gen_plugin_cb_start(from, type, wr);
-}
-
-static void gen_wrapped(enum plugin_gen_from from,
- enum plugin_gen_cb type, void (*func)(void))
-{
- gen_plugin_cb_start(from, type, 0);
- func();
- tcg_gen_plugin_cb_end();
-}
+static void inject_cb(struct qemu_plugin_dyn_cb *cb)
-static void plugin_gen_empty_callback(enum plugin_gen_from from)
{
- switch (from) {
- case PLUGIN_GEN_AFTER_INSN:
- gen_wrapped(from, PLUGIN_GEN_DISABLE_MEM_HELPER,
- gen_empty_mem_helper);
+ switch (cb->type) {
+ case PLUGIN_CB_REGULAR:
+ gen_udata_cb(cb);
break;
- case PLUGIN_GEN_FROM_INSN:
- /*
- * Note: plugin_gen_inject() relies on ENABLE_MEM_HELPER being
- * the first callback of an instruction
- */
- gen_wrapped(from, PLUGIN_GEN_ENABLE_MEM_HELPER,
- gen_empty_mem_helper);
- /* fall through */
- case PLUGIN_GEN_FROM_TB:
- gen_wrapped(from, PLUGIN_GEN_CB_UDATA, gen_empty_udata_cb_no_rwg);
- gen_wrapped(from, PLUGIN_GEN_CB_UDATA_R, gen_empty_udata_cb_no_wg);
- gen_wrapped(from, PLUGIN_GEN_CB_INLINE, gen_empty_inline_cb);
+ case PLUGIN_CB_INLINE:
+ gen_inline_cb(cb);
break;
default:
g_assert_not_reached();
}
}
-void plugin_gen_empty_mem_callback(TCGv_i64 addr, uint32_t info)
+static void inject_mem_cb(struct qemu_plugin_dyn_cb *cb,
+ enum qemu_plugin_mem_rw rw,
+ qemu_plugin_meminfo_t meminfo, TCGv_i64 addr)
{
- enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info);
-
- gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, PLUGIN_GEN_CB_MEM, rw);
- gen_empty_mem_cb(addr, info);
- tcg_gen_plugin_cb_end();
-
- gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, PLUGIN_GEN_CB_INLINE, rw);
- gen_empty_inline_cb();
- tcg_gen_plugin_cb_end();
-}
-
-static TCGOp *find_op(TCGOp *op, TCGOpcode opc)
-{
- while (op) {
- if (op->opc == opc) {
- return op;
+ if (cb->rw & rw) {
+ switch (cb->type) {
+ case PLUGIN_CB_MEM_REGULAR:
+ gen_mem_cb(cb, meminfo, addr);
+ break;
+ default:
+ inject_cb(cb);
+ break;
}
- op = QTAILQ_NEXT(op, link);
}
- return NULL;
-}
-
-static TCGOp *rm_ops_range(TCGOp *begin, TCGOp *end)
-{
- TCGOp *ret = QTAILQ_NEXT(end, link);
-
- QTAILQ_REMOVE_SEVERAL(&tcg_ctx->ops, begin, end, link);
- return ret;
-}
-
-/* remove all ops until (and including) plugin_cb_end */
-static TCGOp *rm_ops(TCGOp *op)
-{
- TCGOp *end_op = find_op(op, INDEX_op_plugin_cb_end);
-
- tcg_debug_assert(end_op);
- return rm_ops_range(op, end_op);
-}
-
-static TCGOp *copy_op_nocheck(TCGOp **begin_op, TCGOp *op)
-{
- TCGOp *old_op = QTAILQ_NEXT(*begin_op, link);
- unsigned nargs = old_op->nargs;
-
- *begin_op = old_op;
- op = tcg_op_insert_after(tcg_ctx, op, old_op->opc, nargs);
- memcpy(op->args, old_op->args, sizeof(op->args[0]) * nargs);
-
- return op;
-}
-
-static TCGOp *copy_op(TCGOp **begin_op, TCGOp *op, TCGOpcode opc)
-{
- op = copy_op_nocheck(begin_op, op);
- tcg_debug_assert((*begin_op)->opc == opc);
- return op;
-}
-
-static TCGOp *copy_const_ptr(TCGOp **begin_op, TCGOp *op, void *ptr)
-{
- if (UINTPTR_MAX == UINT32_MAX) {
- /* mov_i32 */
- op = copy_op(begin_op, op, INDEX_op_mov_i32);
- op->args[1] = tcgv_i32_arg(tcg_constant_i32((uintptr_t)ptr));
- } else {
- /* mov_i64 */
- op = copy_op(begin_op, op, INDEX_op_mov_i64);
- op->args[1] = tcgv_i64_arg(tcg_constant_i64((uintptr_t)ptr));
- }
- return op;
-}
-
-static TCGOp *copy_ld_i32(TCGOp **begin_op, TCGOp *op)
-{
- return copy_op(begin_op, op, INDEX_op_ld_i32);
-}
-
-static TCGOp *copy_ext_i32_ptr(TCGOp **begin_op, TCGOp *op)
-{
- if (UINTPTR_MAX == UINT32_MAX) {
- op = copy_op(begin_op, op, INDEX_op_mov_i32);
- } else {
- op = copy_op(begin_op, op, INDEX_op_ext_i32_i64);
- }
- return op;
-}
-
-static TCGOp *copy_add_ptr(TCGOp **begin_op, TCGOp *op)
-{
- if (UINTPTR_MAX == UINT32_MAX) {
- op = copy_op(begin_op, op, INDEX_op_add_i32);
- } else {
- op = copy_op(begin_op, op, INDEX_op_add_i64);
- }
- return op;
-}
-
-static TCGOp *copy_ld_i64(TCGOp **begin_op, TCGOp *op)
-{
- if (TCG_TARGET_REG_BITS == 32) {
- /* 2x ld_i32 */
- op = copy_ld_i32(begin_op, op);
- op = copy_ld_i32(begin_op, op);
- } else {
- /* ld_i64 */
- op = copy_op(begin_op, op, INDEX_op_ld_i64);
- }
- return op;
-}
-
-static TCGOp *copy_st_i64(TCGOp **begin_op, TCGOp *op)
-{
- if (TCG_TARGET_REG_BITS == 32) {
- /* 2x st_i32 */
- op = copy_op(begin_op, op, INDEX_op_st_i32);
- op = copy_op(begin_op, op, INDEX_op_st_i32);
- } else {
- /* st_i64 */
- op = copy_op(begin_op, op, INDEX_op_st_i64);
- }
- return op;
-}
-
-static TCGOp *copy_add_i64(TCGOp **begin_op, TCGOp *op, uint64_t v)
-{
- if (TCG_TARGET_REG_BITS == 32) {
- /* all 32-bit backends must implement add2_i32 */
- g_assert(TCG_TARGET_HAS_add2_i32);
- op = copy_op(begin_op, op, INDEX_op_add2_i32);
- op->args[4] = tcgv_i32_arg(tcg_constant_i32(v));
- op->args[5] = tcgv_i32_arg(tcg_constant_i32(v >> 32));
- } else {
- op = copy_op(begin_op, op, INDEX_op_add_i64);
- op->args[2] = tcgv_i64_arg(tcg_constant_i64(v));
- }
- return op;
-}
-
-static TCGOp *copy_mul_i32(TCGOp **begin_op, TCGOp *op, uint32_t v)
-{
- op = copy_op(begin_op, op, INDEX_op_mul_i32);
- op->args[2] = tcgv_i32_arg(tcg_constant_i32(v));
- return op;
-}
-
-static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op)
-{
- if (UINTPTR_MAX == UINT32_MAX) {
- /* st_i32 */
- op = copy_op(begin_op, op, INDEX_op_st_i32);
- } else {
- /* st_i64 */
- op = copy_st_i64(begin_op, op);
- }
- return op;
-}
-
-static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *func, int *cb_idx)
-{
- TCGOp *old_op;
- int func_idx;
-
- /* copy all ops until the call */
- do {
- op = copy_op_nocheck(begin_op, op);
- } while (op->opc != INDEX_op_call);
-
- /* fill in the op call */
- old_op = *begin_op;
- TCGOP_CALLI(op) = TCGOP_CALLI(old_op);
- TCGOP_CALLO(op) = TCGOP_CALLO(old_op);
- tcg_debug_assert(op->life == 0);
-
- func_idx = TCGOP_CALLO(op) + TCGOP_CALLI(op);
- *cb_idx = func_idx;
- op->args[func_idx] = (uintptr_t)func;
-
- return op;
-}
-
-/*
- * When we append/replace ops here we are sensitive to changing patterns of
- * TCGOps generated by the tcg_gen_FOO calls when we generated the
- * empty callbacks. This will assert very quickly in a debug build as
- * we assert the ops we are replacing are the correct ones.
- */
-static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
- TCGOp *begin_op, TCGOp *op, int *cb_idx)
-{
- /* const_ptr */
- op = copy_const_ptr(&begin_op, op, cb->userp);
-
- /* copy the ld_i32, but note that we only have to copy it once */
- if (*cb_idx == -1) {
- op = copy_op(&begin_op, op, INDEX_op_ld_i32);
- } else {
- begin_op = QTAILQ_NEXT(begin_op, link);
- tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
- }
-
- /* call */
- op = copy_call(&begin_op, op, cb->f.vcpu_udata, cb_idx);
-
- return op;
-}
-
-static TCGOp *append_inline_cb(const struct qemu_plugin_dyn_cb *cb,
- TCGOp *begin_op, TCGOp *op,
- int *unused)
-{
- char *ptr = cb->inline_insn.entry.score->data->data;
- size_t elem_size = g_array_get_element_size(
- cb->inline_insn.entry.score->data);
- size_t offset = cb->inline_insn.entry.offset;
-
- op = copy_ld_i32(&begin_op, op);
- op = copy_mul_i32(&begin_op, op, elem_size);
- op = copy_ext_i32_ptr(&begin_op, op);
- op = copy_const_ptr(&begin_op, op, ptr + offset);
- op = copy_add_ptr(&begin_op, op);
- op = copy_ld_i64(&begin_op, op);
- op = copy_add_i64(&begin_op, op, cb->inline_insn.imm);
- op = copy_st_i64(&begin_op, op);
- return op;
-}
-
-static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
- TCGOp *begin_op, TCGOp *op, int *cb_idx)
-{
- enum plugin_gen_cb type = begin_op->args[1];
-
- tcg_debug_assert(type == PLUGIN_GEN_CB_MEM);
-
- /* const_i32 == mov_i32 ("info", so it remains as is) */
- op = copy_op(&begin_op, op, INDEX_op_mov_i32);
-
- /* const_ptr */
- op = copy_const_ptr(&begin_op, op, cb->userp);
-
- /* copy the ld_i32, but note that we only have to copy it once */
- if (*cb_idx == -1) {
- op = copy_op(&begin_op, op, INDEX_op_ld_i32);
- } else {
- begin_op = QTAILQ_NEXT(begin_op, link);
- tcg_debug_assert(begin_op && begin_op->opc == INDEX_op_ld_i32);
- }
-
- if (type == PLUGIN_GEN_CB_MEM) {
- /* call */
- op = copy_call(&begin_op, op, cb->f.vcpu_udata, cb_idx);
- }
-
- return op;
-}
-
-typedef TCGOp *(*inject_fn)(const struct qemu_plugin_dyn_cb *cb,
- TCGOp *begin_op, TCGOp *op, int *intp);
-typedef bool (*op_ok_fn)(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb);
-
-static bool op_ok(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
-{
- return true;
}
-static bool op_rw(const TCGOp *op, const struct qemu_plugin_dyn_cb *cb)
-{
- int w;
-
- w = op->args[2];
- return !!(cb->rw & (w + 1));
-}
-
-static void inject_cb_type(const GArray *cbs, TCGOp *begin_op,
- inject_fn inject, op_ok_fn ok)
+static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
{
- TCGOp *end_op;
- TCGOp *op;
- int cb_idx = -1;
- int i;
-
- if (!cbs || cbs->len == 0) {
- rm_ops(begin_op);
- return;
- }
-
- end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
- tcg_debug_assert(end_op);
-
- op = end_op;
- for (i = 0; i < cbs->len; i++) {
- struct qemu_plugin_dyn_cb *cb =
- &g_array_index(cbs, struct qemu_plugin_dyn_cb, i);
+ TCGOp *op, *next;
+ int insn_idx = -1;
- if (!ok(begin_op, cb)) {
- continue;
+ if (unlikely(qemu_loglevel_mask(LOG_TB_OP_PLUGIN)
+ && qemu_log_in_addr_range(plugin_tb->vaddr))) {
+ FILE *logfile = qemu_log_trylock();
+ if (logfile) {
+ fprintf(logfile, "OP before plugin injection:\n");
+ tcg_dump_ops(tcg_ctx, logfile, false);
+ fprintf(logfile, "\n");
+ qemu_log_unlock(logfile);
}
- op = inject(cb, begin_op, op, &cb_idx);
- }
- rm_ops_range(begin_op, end_op);
-}
-
-static void
-inject_udata_cb(const GArray *cbs, TCGOp *begin_op)
-{
- inject_cb_type(cbs, begin_op, append_udata_cb, op_ok);
-}
-
-static void
-inject_inline_cb(const GArray *cbs, TCGOp *begin_op, op_ok_fn ok)
-{
- inject_cb_type(cbs, begin_op, append_inline_cb, ok);
-}
-
-static void
-inject_mem_cb(const GArray *cbs, TCGOp *begin_op)
-{
- inject_cb_type(cbs, begin_op, append_mem_cb, op_rw);
-}
-
-/* we could change the ops in place, but we can reuse more code by copying */
-static void inject_mem_helper(TCGOp *begin_op, GArray *arr)
-{
- TCGOp *orig_op = begin_op;
- TCGOp *end_op;
- TCGOp *op;
-
- end_op = find_op(begin_op, INDEX_op_plugin_cb_end);
- tcg_debug_assert(end_op);
-
- /* const ptr */
- op = copy_const_ptr(&begin_op, end_op, arr);
-
- /* st_ptr */
- op = copy_st_ptr(&begin_op, op);
-
- rm_ops_range(orig_op, end_op);
-}
-
-/*
- * Tracking memory accesses performed from helpers requires extra work.
- * If an instruction is emulated with helpers, we do two things:
- * (1) copy the CB descriptors, and keep track of it so that they can be
- * freed later on, and (2) point CPUState.plugin_mem_cbs to the descriptors, so
- * that we can read them at run-time (i.e. when the helper executes).
- * This run-time access is performed from qemu_plugin_vcpu_mem_cb.
- *
- * Note that plugin_gen_disable_mem_helpers undoes (2). Since it
- * is possible that the code we generate after the instruction is
- * dead, we also add checks before generating tb_exit etc.
- */
-static void inject_mem_enable_helper(struct qemu_plugin_tb *ptb,
- struct qemu_plugin_insn *plugin_insn,
- TCGOp *begin_op)
-{
- GArray *cbs[2];
- GArray *arr;
- size_t n_cbs, i;
-
- cbs[0] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR];
- cbs[1] = plugin_insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
-
- n_cbs = 0;
- for (i = 0; i < ARRAY_SIZE(cbs); i++) {
- n_cbs += cbs[i]->len;
- }
-
- plugin_insn->mem_helper = plugin_insn->calls_helpers && n_cbs;
- if (likely(!plugin_insn->mem_helper)) {
- rm_ops(begin_op);
- return;
}
- ptb->mem_helper = true;
- arr = g_array_sized_new(false, false,
- sizeof(struct qemu_plugin_dyn_cb), n_cbs);
-
- for (i = 0; i < ARRAY_SIZE(cbs); i++) {
- g_array_append_vals(arr, cbs[i]->data, cbs[i]->len);
- }
-
- qemu_plugin_add_dyn_cb_arr(arr);
- inject_mem_helper(begin_op, arr);
-}
-
-static void inject_mem_disable_helper(struct qemu_plugin_insn *plugin_insn,
- TCGOp *begin_op)
-{
- if (likely(!plugin_insn->mem_helper)) {
- rm_ops(begin_op);
- return;
- }
- inject_mem_helper(begin_op, NULL);
-}
-
-/* called before finishing a TB with exit_tb, goto_tb or goto_ptr */
-void plugin_gen_disable_mem_helpers(void)
-{
/*
- * We could emit the clearing unconditionally and be done. However, this can
- * be wasteful if for instance plugins don't track memory accesses, or if
- * most TBs don't use helpers. Instead, emit the clearing iff the TB calls
- * helpers that might access guest memory.
- *
- * Note: we do not reset plugin_tb->mem_helper here; a TB might have several
- * exit points, and we want to emit the clearing from all of them.
+ * While injecting code, we cannot afford to reuse any ebb temps
+ * that might be live within the existing opcode stream.
+ * The simplest solution is to release them all and create new.
*/
- if (!tcg_ctx->plugin_tb->mem_helper) {
- return;
- }
- tcg_gen_st_ptr(tcg_constant_ptr(NULL), tcg_env,
- offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env));
-}
-
-static void plugin_gen_tb_udata(const struct qemu_plugin_tb *ptb,
- TCGOp *begin_op)
-{
- inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR], begin_op);
-}
-
-static void plugin_gen_tb_udata_r(const struct qemu_plugin_tb *ptb,
- TCGOp *begin_op)
-{
- inject_udata_cb(ptb->cbs[PLUGIN_CB_REGULAR_R], begin_op);
-}
-
-static void plugin_gen_tb_inline(const struct qemu_plugin_tb *ptb,
- TCGOp *begin_op)
-{
- inject_inline_cb(ptb->cbs[PLUGIN_CB_INLINE], begin_op, op_ok);
-}
+ memset(tcg_ctx->free_temps, 0, sizeof(tcg_ctx->free_temps));
-static void plugin_gen_insn_udata(const struct qemu_plugin_tb *ptb,
- TCGOp *begin_op, int insn_idx)
-{
- struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-
- inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR], begin_op);
-}
-
-static void plugin_gen_insn_udata_r(const struct qemu_plugin_tb *ptb,
- TCGOp *begin_op, int insn_idx)
-{
- struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-
- inject_udata_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_REGULAR_R], begin_op);
-}
-
-static void plugin_gen_insn_inline(const struct qemu_plugin_tb *ptb,
- TCGOp *begin_op, int insn_idx)
-{
- struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
- inject_inline_cb(insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE],
- begin_op, op_ok);
-}
-
-static void plugin_gen_mem_regular(const struct qemu_plugin_tb *ptb,
- TCGOp *begin_op, int insn_idx)
-{
- struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
- inject_mem_cb(insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR], begin_op);
-}
-
-static void plugin_gen_mem_inline(const struct qemu_plugin_tb *ptb,
- TCGOp *begin_op, int insn_idx)
-{
- const GArray *cbs;
- struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
-
- cbs = insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE];
- inject_inline_cb(cbs, begin_op, op_rw);
-}
-
-static void plugin_gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
- TCGOp *begin_op, int insn_idx)
-{
- struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
- inject_mem_enable_helper(ptb, insn, begin_op);
-}
-
-static void plugin_gen_disable_mem_helper(struct qemu_plugin_tb *ptb,
- TCGOp *begin_op, int insn_idx)
-{
- struct qemu_plugin_insn *insn = g_ptr_array_index(ptb->insns, insn_idx);
- inject_mem_disable_helper(insn, begin_op);
-}
-
-/* #define DEBUG_PLUGIN_GEN_OPS */
-static void pr_ops(void)
-{
-#ifdef DEBUG_PLUGIN_GEN_OPS
- TCGOp *op;
- int i = 0;
-
- QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
- const char *name = "";
- const char *type = "";
-
- if (op->opc == INDEX_op_plugin_cb_start) {
- switch (op->args[0]) {
- case PLUGIN_GEN_FROM_TB:
- name = "tb";
- break;
- case PLUGIN_GEN_FROM_INSN:
- name = "insn";
- break;
- case PLUGIN_GEN_FROM_MEM:
- name = "mem";
- break;
- case PLUGIN_GEN_AFTER_INSN:
- name = "after insn";
- break;
- default:
- break;
- }
- switch (op->args[1]) {
- case PLUGIN_GEN_CB_UDATA:
- type = "udata";
- break;
- case PLUGIN_GEN_CB_INLINE:
- type = "inline";
- break;
- case PLUGIN_GEN_CB_MEM:
- type = "mem";
- break;
- case PLUGIN_GEN_ENABLE_MEM_HELPER:
- type = "enable mem helper";
- break;
- case PLUGIN_GEN_DISABLE_MEM_HELPER:
- type = "disable mem helper";
- break;
- default:
- break;
- }
- }
- printf("op[%2i]: %s %s %s\n", i, tcg_op_defs[op->opc].name, name, type);
- i++;
- }
-#endif
-}
-
-static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb)
-{
- TCGOp *op;
- int insn_idx = -1;
-
- pr_ops();
-
- QTAILQ_FOREACH(op, &tcg_ctx->ops, link) {
+ QTAILQ_FOREACH_SAFE(op, &tcg_ctx->ops, link, next) {
switch (op->opc) {
case INDEX_op_insn_start:
insn_idx++;
break;
- case INDEX_op_plugin_cb_start:
+
+ case INDEX_op_plugin_cb:
{
enum plugin_gen_from from = op->args[0];
- enum plugin_gen_cb type = op->args[1];
+ struct qemu_plugin_insn *insn = NULL;
+ const GArray *cbs;
+ int i, n;
+
+ if (insn_idx >= 0) {
+ insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
+ }
+
+ tcg_ctx->emit_before_op = op;
switch (from) {
- case PLUGIN_GEN_FROM_TB:
- {
- g_assert(insn_idx == -1);
-
- switch (type) {
- case PLUGIN_GEN_CB_UDATA:
- plugin_gen_tb_udata(plugin_tb, op);
- break;
- case PLUGIN_GEN_CB_UDATA_R:
- plugin_gen_tb_udata_r(plugin_tb, op);
- break;
- case PLUGIN_GEN_CB_INLINE:
- plugin_gen_tb_inline(plugin_tb, op);
- break;
- default:
- g_assert_not_reached();
+ case PLUGIN_GEN_AFTER_TB:
+ if (plugin_tb->mem_helper) {
+ gen_disable_mem_helper();
}
break;
- }
- case PLUGIN_GEN_FROM_INSN:
- {
- g_assert(insn_idx >= 0);
-
- switch (type) {
- case PLUGIN_GEN_CB_UDATA:
- plugin_gen_insn_udata(plugin_tb, op, insn_idx);
- break;
- case PLUGIN_GEN_CB_UDATA_R:
- plugin_gen_insn_udata_r(plugin_tb, op, insn_idx);
- break;
- case PLUGIN_GEN_CB_INLINE:
- plugin_gen_insn_inline(plugin_tb, op, insn_idx);
- break;
- case PLUGIN_GEN_ENABLE_MEM_HELPER:
- plugin_gen_enable_mem_helper(plugin_tb, op, insn_idx);
- break;
- default:
- g_assert_not_reached();
+
+ case PLUGIN_GEN_AFTER_INSN:
+ assert(insn != NULL);
+ if (insn->mem_helper) {
+ gen_disable_mem_helper();
}
break;
- }
- case PLUGIN_GEN_FROM_MEM:
- {
- g_assert(insn_idx >= 0);
-
- switch (type) {
- case PLUGIN_GEN_CB_MEM:
- plugin_gen_mem_regular(plugin_tb, op, insn_idx);
- break;
- case PLUGIN_GEN_CB_INLINE:
- plugin_gen_mem_inline(plugin_tb, op, insn_idx);
- break;
- default:
- g_assert_not_reached();
- }
+ case PLUGIN_GEN_FROM_TB:
+ assert(insn == NULL);
+
+ cbs = plugin_tb->cbs;
+ for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
+ inject_cb(
+ &g_array_index(cbs, struct qemu_plugin_dyn_cb, i));
+ }
break;
- }
- case PLUGIN_GEN_AFTER_INSN:
- {
- g_assert(insn_idx >= 0);
-
- switch (type) {
- case PLUGIN_GEN_DISABLE_MEM_HELPER:
- plugin_gen_disable_mem_helper(plugin_tb, op, insn_idx);
- break;
- default:
- g_assert_not_reached();
+
+ case PLUGIN_GEN_FROM_INSN:
+ assert(insn != NULL);
+
+ gen_enable_mem_helper(plugin_tb, insn);
+
+ cbs = insn->insn_cbs;
+ for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
+ inject_cb(
+ &g_array_index(cbs, struct qemu_plugin_dyn_cb, i));
}
break;
- }
+
default:
g_assert_not_reached();
}
+
+ tcg_ctx->emit_before_op = NULL;
+ tcg_op_remove(tcg_ctx, op);
+ break;
+ }
+
+ case INDEX_op_plugin_mem_cb:
+ {
+ TCGv_i64 addr = temp_tcgv_i64(arg_temp(op->args[0]));
+ qemu_plugin_meminfo_t meminfo = op->args[1];
+ enum qemu_plugin_mem_rw rw =
+ (qemu_plugin_mem_is_store(meminfo)
+ ? QEMU_PLUGIN_MEM_W : QEMU_PLUGIN_MEM_R);
+ struct qemu_plugin_insn *insn;
+ const GArray *cbs;
+ int i, n;
+
+ assert(insn_idx >= 0);
+ insn = g_ptr_array_index(plugin_tb->insns, insn_idx);
+
+ tcg_ctx->emit_before_op = op;
+
+ cbs = insn->mem_cbs;
+ for (i = 0, n = (cbs ? cbs->len : 0); i < n; i++) {
+ inject_mem_cb(&g_array_index(cbs, struct qemu_plugin_dyn_cb, i),
+ rw, meminfo, addr);
+ }
+
+ tcg_ctx->emit_before_op = NULL;
+ tcg_op_remove(tcg_ctx, op);
break;
}
+
default:
/* plugins don't care about any other ops */
break;
}
}
- pr_ops();
}
bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
@@ -873,13 +310,10 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_state->event_mask)) {
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
- int i;
/* reset callbacks */
- for (i = 0; i < PLUGIN_N_CB_SUBTYPES; i++) {
- if (ptb->cbs[i]) {
- g_array_set_size(ptb->cbs[i], 0);
- }
+ if (ptb->cbs) {
+ g_array_set_size(ptb->cbs, 0);
}
ptb->n = 0;
@@ -892,7 +326,7 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
ptb->mem_only = mem_only;
ptb->mem_helper = false;
- plugin_gen_empty_callback(PLUGIN_GEN_FROM_TB);
+ tcg_gen_plugin_cb(PLUGIN_GEN_FROM_TB);
}
tcg_ctx->plugin_insn = NULL;
@@ -903,11 +337,34 @@ bool plugin_gen_tb_start(CPUState *cpu, const DisasContextBase *db,
void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
{
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
- struct qemu_plugin_insn *pinsn;
+ struct qemu_plugin_insn *insn;
+ size_t n = db->num_insns;
+ vaddr pc;
+
+ assert(n >= 1);
+ ptb->n = n;
+ if (n <= ptb->insns->len) {
+ insn = g_ptr_array_index(ptb->insns, n - 1);
+ g_byte_array_set_size(insn->data, 0);
+ } else {
+ assert(n - 1 == ptb->insns->len);
+ insn = g_new0(struct qemu_plugin_insn, 1);
+ insn->data = g_byte_array_sized_new(4);
+ g_ptr_array_add(ptb->insns, insn);
+ }
- pinsn = qemu_plugin_tb_insn_get(ptb, db->pc_next);
- tcg_ctx->plugin_insn = pinsn;
- plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
+ tcg_ctx->plugin_insn = insn;
+ insn->calls_helpers = false;
+ insn->mem_helper = false;
+ if (insn->insn_cbs) {
+ g_array_set_size(insn->insn_cbs, 0);
+ }
+ if (insn->mem_cbs) {
+ g_array_set_size(insn->mem_cbs, 0);
+ }
+
+ pc = db->pc_next;
+ insn->vaddr = pc;
/*
* Detect page crossing to get the new host address.
@@ -915,21 +372,23 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
* fetching instructions from a region not backed by RAM.
*/
if (ptb->haddr1 == NULL) {
- pinsn->haddr = NULL;
+ insn->haddr = NULL;
} else if (is_same_page(db, db->pc_next)) {
- pinsn->haddr = ptb->haddr1 + pinsn->vaddr - ptb->vaddr;
+ insn->haddr = ptb->haddr1 + pc - ptb->vaddr;
} else {
if (ptb->vaddr2 == -1) {
ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first);
get_page_addr_code_hostp(cpu_env(cpu), ptb->vaddr2, &ptb->haddr2);
}
- pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2;
+ insn->haddr = ptb->haddr2 + pc - ptb->vaddr2;
}
+
+ tcg_gen_plugin_cb(PLUGIN_GEN_FROM_INSN);
}
void plugin_gen_insn_end(void)
{
- plugin_gen_empty_callback(PLUGIN_GEN_AFTER_INSN);
+ tcg_gen_plugin_cb(PLUGIN_GEN_AFTER_INSN);
}
/*
diff --git a/accel/tcg/plugin-helpers.h b/accel/tcg/plugin-helpers.h
deleted file mode 100644
index 11796436f3..0000000000
--- a/accel/tcg/plugin-helpers.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CONFIG_PLUGIN
-DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb_no_wg, TCG_CALL_NO_WG | TCG_CALL_PLUGIN, void, i32, ptr)
-DEF_HELPER_FLAGS_2(plugin_vcpu_udata_cb_no_rwg, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, ptr)
-DEF_HELPER_FLAGS_4(plugin_vcpu_mem_cb, TCG_CALL_NO_RWG | TCG_CALL_PLUGIN, void, i32, i32, i64, ptr)
-#endif
diff --git a/include/exec/helper-gen-common.h b/include/exec/helper-gen-common.h
index 5d6d78a625..834590dc4e 100644
--- a/include/exec/helper-gen-common.h
+++ b/include/exec/helper-gen-common.h
@@ -11,8 +11,4 @@
#include "exec/helper-gen.h.inc"
#undef HELPER_H
-#define HELPER_H "accel/tcg/plugin-helpers.h"
-#include "exec/helper-gen.h.inc"
-#undef HELPER_H
-
#endif /* HELPER_GEN_COMMON_H */
diff --git a/include/exec/helper-gen.h.inc b/include/exec/helper-gen.h.inc
index d9fd3ed72a..dabe138e20 100644
--- a/include/exec/helper-gen.h.inc
+++ b/include/exec/helper-gen.h.inc
@@ -14,7 +14,8 @@
extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \
{ \
- tcg_gen_call0(&glue(helper_info_, name), dh_retvar(ret)); \
+ tcg_gen_call0(glue(helper_info_,name).func, \
+ &glue(helper_info_,name), dh_retvar(ret)); \
}
#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
@@ -22,7 +23,8 @@ extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1)) \
{ \
- tcg_gen_call1(&glue(helper_info_, name), dh_retvar(ret), \
+ tcg_gen_call1(glue(helper_info_,name).func, \
+ &glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1)); \
}
@@ -31,7 +33,8 @@ extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2)) \
{ \
- tcg_gen_call2(&glue(helper_info_, name), dh_retvar(ret), \
+ tcg_gen_call2(glue(helper_info_,name).func, \
+ &glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2)); \
}
@@ -40,7 +43,8 @@ extern TCGHelperInfo glue(helper_info_, name); \
static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \
{ \
- tcg_gen_call3(&glue(helper_info_, name), dh_retvar(ret), \
+ tcg_gen_call3(glue(helper_info_,name).func, \
+ &glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3)); \
}
@@ -50,7 +54,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), \
dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \
{ \
- tcg_gen_call4(&glue(helper_info_, name), dh_retvar(ret), \
+ tcg_gen_call4(glue(helper_info_,name).func, \
+ &glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), \
dh_arg(t3, 3), dh_arg(t4, 4)); \
}
@@ -61,7 +66,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5)) \
{ \
- tcg_gen_call5(&glue(helper_info_, name), dh_retvar(ret), \
+ tcg_gen_call5(glue(helper_info_,name).func, \
+ &glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5)); \
}
@@ -72,7 +78,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6)) \
{ \
- tcg_gen_call6(&glue(helper_info_, name), dh_retvar(ret), \
+ tcg_gen_call6(glue(helper_info_,name).func, \
+ &glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6)); \
}
@@ -84,7 +91,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6), \
dh_arg_decl(t7, 7)) \
{ \
- tcg_gen_call7(&glue(helper_info_, name), dh_retvar(ret), \
+ tcg_gen_call7(glue(helper_info_,name).func, \
+ &glue(helper_info_,name), dh_retvar(ret), \
dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \
dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6), \
dh_arg(t7, 7)); \
diff --git a/include/exec/helper-proto-common.h b/include/exec/helper-proto-common.h
index 8b67170a22..16782ef46c 100644
--- a/include/exec/helper-proto-common.h
+++ b/include/exec/helper-proto-common.h
@@ -13,8 +13,4 @@
#include "exec/helper-proto.h.inc"
#undef HELPER_H
-#define HELPER_H "accel/tcg/plugin-helpers.h"
-#include "exec/helper-proto.h.inc"
-#undef HELPER_H
-
#endif /* HELPER_PROTO_COMMON_H */
diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h
index c4552b5061..f333f33198 100644
--- a/include/exec/plugin-gen.h
+++ b/include/exec/plugin-gen.h
@@ -25,7 +25,6 @@ void plugin_gen_insn_start(CPUState *cpu, const struct DisasContextBase *db);
void plugin_gen_insn_end(void);
void plugin_gen_disable_mem_helpers(void);
-void plugin_gen_empty_mem_callback(TCGv_i64 addr, uint32_t info);
#else /* !CONFIG_PLUGIN */
@@ -48,9 +47,6 @@ static inline void plugin_gen_tb_end(CPUState *cpu, size_t num_insns)
static inline void plugin_gen_disable_mem_helpers(void)
{ }
-static inline void plugin_gen_empty_mem_callback(TCGv_i64 addr, uint32_t info)
-{ }
-
#endif /* CONFIG_PLUGIN */
#endif /* QEMU_PLUGIN_GEN_H */
diff --git a/include/qemu/log.h b/include/qemu/log.h
index df59bfabcd..e10e24cd4f 100644
--- a/include/qemu/log.h
+++ b/include/qemu/log.h
@@ -36,6 +36,7 @@ bool qemu_log_separate(void);
#define LOG_STRACE (1 << 19)
#define LOG_PER_THREAD (1 << 20)
#define CPU_LOG_TB_VPU (1 << 21)
+#define LOG_TB_OP_PLUGIN (1 << 22)
/* Lock/unlock output. */
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index 41db748eda..18062528c1 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -67,16 +67,9 @@ union qemu_plugin_cb_sig {
};
enum plugin_dyn_cb_type {
- PLUGIN_CB_INSN,
- PLUGIN_CB_MEM,
- PLUGIN_N_CB_TYPES,
-};
-
-enum plugin_dyn_cb_subtype {
PLUGIN_CB_REGULAR,
- PLUGIN_CB_REGULAR_R,
+ PLUGIN_CB_MEM_REGULAR,
PLUGIN_CB_INLINE,
- PLUGIN_N_CB_SUBTYPES,
};
/*
@@ -85,14 +78,17 @@ enum plugin_dyn_cb_subtype {
* instance of a callback to be called upon the execution of a particular TB.
*/
struct qemu_plugin_dyn_cb {
- union qemu_plugin_cb_sig f;
void *userp;
- enum plugin_dyn_cb_subtype type;
+ enum plugin_dyn_cb_type type;
/* @rw applies to mem callbacks only (both regular and inline) */
enum qemu_plugin_mem_rw rw;
/* fields specific to each dyn_cb type go here */
union {
struct {
+ union qemu_plugin_cb_sig f;
+ TCGHelperInfo *info;
+ } regular;
+ struct {
qemu_plugin_u64 entry;
enum qemu_plugin_op op;
uint64_t imm;
@@ -105,7 +101,8 @@ struct qemu_plugin_insn {
GByteArray *data;
uint64_t vaddr;
void *haddr;
- GArray *cbs[PLUGIN_N_CB_TYPES][PLUGIN_N_CB_SUBTYPES];
+ GArray *insn_cbs;
+ GArray *mem_cbs;
bool calls_helpers;
/* if set, the instruction calls helpers that might access guest memory */
@@ -132,21 +129,6 @@ static inline void qemu_plugin_insn_cleanup_fn(gpointer data)
g_byte_array_free(insn->data, true);
}
-static inline struct qemu_plugin_insn *qemu_plugin_insn_alloc(void)
-{
- int i, j;
- struct qemu_plugin_insn *insn = g_new0(struct qemu_plugin_insn, 1);
- insn->data = g_byte_array_sized_new(4);
-
- for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
- for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
- insn->cbs[i][j] = g_array_new(false, false,
- sizeof(struct qemu_plugin_dyn_cb));
- }
- }
- return insn;
-}
-
/* Internal context for this TranslationBlock */
struct qemu_plugin_tb {
GPtrArray *insns;
@@ -160,41 +142,10 @@ struct qemu_plugin_tb {
/* if set, the TB calls helpers that might access guest memory */
bool mem_helper;
- GArray *cbs[PLUGIN_N_CB_SUBTYPES];
+ GArray *cbs;
};
/**
- * qemu_plugin_tb_insn_get(): get next plugin record for translation.
- * @tb: the internal tb context
- * @pc: address of instruction
- */
-static inline
-struct qemu_plugin_insn *qemu_plugin_tb_insn_get(struct qemu_plugin_tb *tb,
- uint64_t pc)
-{
- struct qemu_plugin_insn *insn;
- int i, j;
-
- if (unlikely(tb->n == tb->insns->len)) {
- struct qemu_plugin_insn *new_insn = qemu_plugin_insn_alloc();
- g_ptr_array_add(tb->insns, new_insn);
- }
- insn = g_ptr_array_index(tb->insns, tb->n++);
- g_byte_array_set_size(insn->data, 0);
- insn->calls_helpers = false;
- insn->mem_helper = false;
- insn->vaddr = pc;
-
- for (i = 0; i < PLUGIN_N_CB_TYPES; i++) {
- for (j = 0; j < PLUGIN_N_CB_SUBTYPES; j++) {
- g_array_set_size(insn->cbs[i][j], 0);
- }
- }
-
- return insn;
-}
-
-/**
* struct CPUPluginState - per-CPU state for plugins
* @event_mask: plugin event bitmap. Modified only via async work.
*/
diff --git a/include/tcg/helper-info.h b/include/tcg/helper-info.h
index 7c27d6164a..909fe73afa 100644
--- a/include/tcg/helper-info.h
+++ b/include/tcg/helper-info.h
@@ -12,6 +12,9 @@
#ifdef CONFIG_TCG_INTERPRETER
#include <ffi.h>
#endif
+#include "tcg-target-reg-bits.h"
+
+#define MAX_CALL_IARGS 7
/*
* Describe the calling convention of a given argument type.
diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h
index 2d932a515e..009e2778c5 100644
--- a/include/tcg/tcg-op-common.h
+++ b/include/tcg/tcg-op-common.h
@@ -74,8 +74,8 @@ void tcg_gen_goto_tb(unsigned idx);
*/
void tcg_gen_lookup_and_goto_ptr(void);
-void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr);
-void tcg_gen_plugin_cb_end(void);
+void tcg_gen_plugin_cb(unsigned from);
+void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo);
/* 32 bit ops */
diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h
index b80227fa1c..546eb49c11 100644
--- a/include/tcg/tcg-opc.h
+++ b/include/tcg/tcg-opc.h
@@ -197,8 +197,8 @@ DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
-DEF(plugin_cb_start, 0, 0, 3, TCG_OPF_NOT_PRESENT)
-DEF(plugin_cb_end, 0, 0, 0, TCG_OPF_NOT_PRESENT)
+DEF(plugin_cb, 0, 0, 1, TCG_OPF_NOT_PRESENT)
+DEF(plugin_mem_cb, 0, 1, 1, TCG_OPF_NOT_PRESENT)
/* Replicate ld/st ops for 32 and 64-bit guest addresses. */
DEF(qemu_ld_a32_i32, 1, 1, 1,
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 05a1912f8a..135e36d729 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -39,8 +39,6 @@
/* XXX: make safe guess about sizes */
#define MAX_OP_PER_INSTR 266
-#define MAX_CALL_IARGS 7
-
#define CPU_TEMP_BUF_NLONGS 128
#define TCG_STATIC_FRAME_SIZE (CPU_TEMP_BUF_NLONGS * sizeof(long))
@@ -355,8 +353,6 @@ typedef TCGv_ptr TCGv_env;
#define TCG_CALL_NO_SIDE_EFFECTS 0x0004
/* Helper is G_NORETURN. */
#define TCG_CALL_NO_RETURN 0x0008
-/* Helper is part of Plugins. */
-#define TCG_CALL_PLUGIN 0x0010
/* convenience version of most used call flags */
#define TCG_CALL_NO_RWG TCG_CALL_NO_READ_GLOBALS
@@ -854,19 +850,22 @@ typedef struct TCGTargetOpDef {
bool tcg_op_supported(TCGOpcode op);
-void tcg_gen_call0(TCGHelperInfo *, TCGTemp *ret);
-void tcg_gen_call1(TCGHelperInfo *, TCGTemp *ret, TCGTemp *);
-void tcg_gen_call2(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *);
-void tcg_gen_call3(TCGHelperInfo *, TCGTemp *ret, TCGTemp *,
- TCGTemp *, TCGTemp *);
-void tcg_gen_call4(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *,
+void tcg_gen_call0(void *func, TCGHelperInfo *, TCGTemp *ret);
+void tcg_gen_call1(void *func, TCGHelperInfo *, TCGTemp *ret, TCGTemp *);
+void tcg_gen_call2(void *func, TCGHelperInfo *, TCGTemp *ret,
TCGTemp *, TCGTemp *);
-void tcg_gen_call5(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *,
+void tcg_gen_call3(void *func, TCGHelperInfo *, TCGTemp *ret,
TCGTemp *, TCGTemp *, TCGTemp *);
-void tcg_gen_call6(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *,
+void tcg_gen_call4(void *func, TCGHelperInfo *, TCGTemp *ret,
TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *);
-void tcg_gen_call7(TCGHelperInfo *, TCGTemp *ret, TCGTemp *, TCGTemp *,
+void tcg_gen_call5(void *func, TCGHelperInfo *, TCGTemp *ret,
TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *);
+void tcg_gen_call6(void *func, TCGHelperInfo *, TCGTemp *ret,
+ TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *,
+ TCGTemp *, TCGTemp *);
+void tcg_gen_call7(void *func, TCGHelperInfo *, TCGTemp *ret,
+ TCGTemp *, TCGTemp *, TCGTemp *, TCGTemp *,
+ TCGTemp *, TCGTemp *, TCGTemp *);
TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs);
void tcg_op_remove(TCGContext *s, TCGOp *op);
@@ -1071,5 +1070,6 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n)
}
bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned);
+void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs);
#endif /* TCG_H */
diff --git a/plugins/api.c b/plugins/api.c
index 8fa5a600ac..3912c9cc8f 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -92,12 +92,7 @@ void qemu_plugin_register_vcpu_tb_exec_cb(struct qemu_plugin_tb *tb,
void *udata)
{
if (!tb->mem_only) {
- int index = flags == QEMU_PLUGIN_CB_R_REGS ||
- flags == QEMU_PLUGIN_CB_RW_REGS ?
- PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
-
- plugin_register_dyn_cb__udata(&tb->cbs[index],
- cb, flags, udata);
+ plugin_register_dyn_cb__udata(&tb->cbs, cb, flags, udata);
}
}
@@ -108,8 +103,7 @@ void qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
uint64_t imm)
{
if (!tb->mem_only) {
- plugin_register_inline_op_on_entry(
- &tb->cbs[PLUGIN_CB_INLINE], 0, op, entry, imm);
+ plugin_register_inline_op_on_entry(&tb->cbs, 0, op, entry, imm);
}
}
@@ -119,12 +113,7 @@ void qemu_plugin_register_vcpu_insn_exec_cb(struct qemu_plugin_insn *insn,
void *udata)
{
if (!insn->mem_only) {
- int index = flags == QEMU_PLUGIN_CB_R_REGS ||
- flags == QEMU_PLUGIN_CB_RW_REGS ?
- PLUGIN_CB_REGULAR_R : PLUGIN_CB_REGULAR;
-
- plugin_register_dyn_cb__udata(&insn->cbs[PLUGIN_CB_INSN][index],
- cb, flags, udata);
+ plugin_register_dyn_cb__udata(&insn->insn_cbs, cb, flags, udata);
}
}
@@ -135,8 +124,7 @@ void qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
uint64_t imm)
{
if (!insn->mem_only) {
- plugin_register_inline_op_on_entry(
- &insn->cbs[PLUGIN_CB_INSN][PLUGIN_CB_INLINE], 0, op, entry, imm);
+ plugin_register_inline_op_on_entry(&insn->insn_cbs, 0, op, entry, imm);
}
}
@@ -151,8 +139,7 @@ void qemu_plugin_register_vcpu_mem_cb(struct qemu_plugin_insn *insn,
enum qemu_plugin_mem_rw rw,
void *udata)
{
- plugin_register_vcpu_mem_cb(&insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_REGULAR],
- cb, flags, rw, udata);
+ plugin_register_vcpu_mem_cb(&insn->mem_cbs, cb, flags, rw, udata);
}
void qemu_plugin_register_vcpu_mem_inline_per_vcpu(
@@ -162,8 +149,7 @@ void qemu_plugin_register_vcpu_mem_inline_per_vcpu(
qemu_plugin_u64 entry,
uint64_t imm)
{
- plugin_register_inline_op_on_entry(
- &insn->cbs[PLUGIN_CB_MEM][PLUGIN_CB_INLINE], rw, op, entry, imm);
+ plugin_register_inline_op_on_entry(&insn->mem_cbs, rw, op, entry, imm);
}
void qemu_plugin_register_vcpu_tb_trans_cb(qemu_plugin_id_t id,
diff --git a/plugins/core.c b/plugins/core.c
index 11ca20e626..0213513ec6 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -307,7 +307,7 @@ static struct qemu_plugin_dyn_cb *plugin_get_dyn_cb(GArray **arr)
GArray *cbs = *arr;
if (!cbs) {
- cbs = g_array_sized_new(false, false,
+ cbs = g_array_sized_new(false, true,
sizeof(struct qemu_plugin_dyn_cb), 1);
*arr = cbs;
}
@@ -338,12 +338,25 @@ void plugin_register_dyn_cb__udata(GArray **arr,
enum qemu_plugin_cb_flags flags,
void *udata)
{
- struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
+ static TCGHelperInfo info[3] = {
+ [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
+ [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
+ /*
+ * Match qemu_plugin_vcpu_udata_cb_t:
+ * void (*)(uint32_t, void *)
+ */
+ [0 ... 2].typemask = (dh_typemask(void, 0) |
+ dh_typemask(i32, 1) |
+ dh_typemask(ptr, 2))
+ };
+ struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
dyn_cb->userp = udata;
- /* Note flags are discarded as unused. */
- dyn_cb->f.vcpu_udata = cb;
dyn_cb->type = PLUGIN_CB_REGULAR;
+ dyn_cb->regular.f.vcpu_udata = cb;
+
+ assert((unsigned)flags < ARRAY_SIZE(info));
+ dyn_cb->regular.info = &info[flags];
}
void plugin_register_vcpu_mem_cb(GArray **arr,
@@ -352,14 +365,38 @@ void plugin_register_vcpu_mem_cb(GArray **arr,
enum qemu_plugin_mem_rw rw,
void *udata)
{
- struct qemu_plugin_dyn_cb *dyn_cb;
+ /*
+ * Expect that the underlying type for enum qemu_plugin_meminfo_t
+ * is either int32_t or uint32_t, aka int or unsigned int.
+ */
+ QEMU_BUILD_BUG_ON(
+ !__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t) &&
+ !__builtin_types_compatible_p(qemu_plugin_meminfo_t, int32_t));
+
+ static TCGHelperInfo info[3] = {
+ [QEMU_PLUGIN_CB_NO_REGS].flags = TCG_CALL_NO_RWG,
+ [QEMU_PLUGIN_CB_R_REGS].flags = TCG_CALL_NO_WG,
+ /*
+ * Match qemu_plugin_vcpu_mem_cb_t:
+ * void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *)
+ */
+ [0 ... 2].typemask =
+ (dh_typemask(void, 0) |
+ dh_typemask(i32, 1) |
+ (__builtin_types_compatible_p(qemu_plugin_meminfo_t, uint32_t)
+ ? dh_typemask(i32, 2) : dh_typemask(s32, 2)) |
+ dh_typemask(i64, 3) |
+ dh_typemask(ptr, 4))
+ };
- dyn_cb = plugin_get_dyn_cb(arr);
+ struct qemu_plugin_dyn_cb *dyn_cb = plugin_get_dyn_cb(arr);
dyn_cb->userp = udata;
- /* Note flags are discarded as unused. */
- dyn_cb->type = PLUGIN_CB_REGULAR;
+ dyn_cb->type = PLUGIN_CB_MEM_REGULAR;
dyn_cb->rw = rw;
- dyn_cb->f.generic = cb;
+ dyn_cb->regular.f.vcpu_mem = cb;
+
+ assert((unsigned)flags < ARRAY_SIZE(info));
+ dyn_cb->regular.info = &info[flags];
}
/*
@@ -510,9 +547,9 @@ void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
break;
}
switch (cb->type) {
- case PLUGIN_CB_REGULAR:
- cb->f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw),
- vaddr, cb->userp);
+ case PLUGIN_CB_MEM_REGULAR:
+ cb->regular.f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw),
+ vaddr, cb->userp);
break;
case PLUGIN_CB_INLINE:
exec_inline_op(cb, cpu->cpu_index);
diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c
index f11043b449..8510160258 100644
--- a/tcg/tcg-op-ldst.c
+++ b/tcg/tcg-op-ldst.c
@@ -161,14 +161,14 @@ plugin_gen_mem_callbacks(TCGv_i64 copy_addr, TCGTemp *orig_addr, MemOpIdx oi,
copy_addr = tcg_temp_ebb_new_i64();
tcg_gen_extu_i32_i64(copy_addr, temp_tcgv_i32(orig_addr));
}
- plugin_gen_empty_mem_callback(copy_addr, info);
+ tcg_gen_plugin_mem_cb(copy_addr, info);
tcg_temp_free_i64(copy_addr);
} else {
if (copy_addr) {
- plugin_gen_empty_mem_callback(copy_addr, info);
+ tcg_gen_plugin_mem_cb(copy_addr, info);
tcg_temp_free_i64(copy_addr);
} else {
- plugin_gen_empty_mem_callback(temp_tcgv_i64(orig_addr), info);
+ tcg_gen_plugin_mem_cb(temp_tcgv_i64(orig_addr), info);
}
}
}
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index aa6bc6f57d..eff3728622 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -312,14 +312,14 @@ void tcg_gen_mb(TCGBar mb_type)
}
}
-void tcg_gen_plugin_cb_start(unsigned from, unsigned type, unsigned wr)
+void tcg_gen_plugin_cb(unsigned from)
{
- tcg_gen_op3(INDEX_op_plugin_cb_start, from, type, wr);
+ tcg_gen_op1(INDEX_op_plugin_cb, from);
}
-void tcg_gen_plugin_cb_end(void)
+void tcg_gen_plugin_mem_cb(TCGv_i64 addr, unsigned meminfo)
{
- tcg_emit_op(INDEX_op_plugin_cb_end, 0);
+ tcg_gen_op2(INDEX_op_plugin_mem_cb, tcgv_i64_arg(addr), meminfo);
}
/* 32 bit ops */
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 6a32656cd4..d827c6d431 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2251,7 +2251,8 @@ bool tcg_op_supported(TCGOpcode op)
static TCGOp *tcg_op_alloc(TCGOpcode opc, unsigned nargs);
-static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
+static void tcg_gen_callN(void *func, TCGHelperInfo *info,
+ TCGTemp *ret, TCGTemp **args)
{
TCGv_i64 extend_free[MAX_CALL_IARGS];
int n_extend = 0;
@@ -2268,9 +2269,7 @@ static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
#ifdef CONFIG_PLUGIN
/* Flag helpers that may affect guest state */
- if (tcg_ctx->plugin_insn &&
- !(info->flags & TCG_CALL_PLUGIN) &&
- !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
+ if (tcg_ctx->plugin_insn && !(info->flags & TCG_CALL_NO_SIDE_EFFECTS)) {
tcg_ctx->plugin_insn->calls_helpers = true;
}
#endif
@@ -2329,7 +2328,7 @@ static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
g_assert_not_reached();
}
}
- op->args[pi++] = (uintptr_t)info->func;
+ op->args[pi++] = (uintptr_t)func;
op->args[pi++] = (uintptr_t)info;
tcg_debug_assert(pi == total_args);
@@ -2345,56 +2344,58 @@ static void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args)
}
}
-void tcg_gen_call0(TCGHelperInfo *info, TCGTemp *ret)
+void tcg_gen_call0(void *func, TCGHelperInfo *info, TCGTemp *ret)
{
- tcg_gen_callN(info, ret, NULL);
+ tcg_gen_callN(func, info, ret, NULL);
}
-void tcg_gen_call1(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
+void tcg_gen_call1(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1)
{
- tcg_gen_callN(info, ret, &t1);
+ tcg_gen_callN(func, info, ret, &t1);
}
-void tcg_gen_call2(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, TCGTemp *t2)
+void tcg_gen_call2(void *func, TCGHelperInfo *info, TCGTemp *ret,
+ TCGTemp *t1, TCGTemp *t2)
{
TCGTemp *args[2] = { t1, t2 };
- tcg_gen_callN(info, ret, args);
+ tcg_gen_callN(func, info, ret, args);
}
-void tcg_gen_call3(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
- TCGTemp *t2, TCGTemp *t3)
+void tcg_gen_call3(void *func, TCGHelperInfo *info, TCGTemp *ret,
+ TCGTemp *t1, TCGTemp *t2, TCGTemp *t3)
{
TCGTemp *args[3] = { t1, t2, t3 };
- tcg_gen_callN(info, ret, args);
+ tcg_gen_callN(func, info, ret, args);
}
-void tcg_gen_call4(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
- TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
+void tcg_gen_call4(void *func, TCGHelperInfo *info, TCGTemp *ret,
+ TCGTemp *t1, TCGTemp *t2, TCGTemp *t3, TCGTemp *t4)
{
TCGTemp *args[4] = { t1, t2, t3, t4 };
- tcg_gen_callN(info, ret, args);
+ tcg_gen_callN(func, info, ret, args);
}
-void tcg_gen_call5(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
+void tcg_gen_call5(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
TCGTemp *t2, TCGTemp *t3, TCGTemp *t4, TCGTemp *t5)
{
TCGTemp *args[5] = { t1, t2, t3, t4, t5 };
- tcg_gen_callN(info, ret, args);
+ tcg_gen_callN(func, info, ret, args);
}
-void tcg_gen_call6(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1, TCGTemp *t2,
- TCGTemp *t3, TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
+void tcg_gen_call6(void *func, TCGHelperInfo *info, TCGTemp *ret,
+ TCGTemp *t1, TCGTemp *t2, TCGTemp *t3,
+ TCGTemp *t4, TCGTemp *t5, TCGTemp *t6)
{
TCGTemp *args[6] = { t1, t2, t3, t4, t5, t6 };
- tcg_gen_callN(info, ret, args);
+ tcg_gen_callN(func, info, ret, args);
}
-void tcg_gen_call7(TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
+void tcg_gen_call7(void *func, TCGHelperInfo *info, TCGTemp *ret, TCGTemp *t1,
TCGTemp *t2, TCGTemp *t3, TCGTemp *t4,
TCGTemp *t5, TCGTemp *t6, TCGTemp *t7)
{
TCGTemp *args[7] = { t1, t2, t3, t4, t5, t6, t7 };
- tcg_gen_callN(info, ret, args);
+ tcg_gen_callN(func, info, ret, args);
}
static void tcg_reg_alloc_start(TCGContext *s)
@@ -2539,6 +2540,15 @@ static const char bswap_flag_name[][6] = {
[TCG_BSWAP_IZ | TCG_BSWAP_OS] = "iz,os",
};
+#ifdef CONFIG_PLUGIN
+static const char * const plugin_from_name[] = {
+ "from-tb",
+ "from-insn",
+ "after-insn",
+ "after-tb",
+};
+#endif
+
static inline bool tcg_regset_single(TCGRegSet d)
{
return (d & (d - 1)) == 0;
@@ -2557,7 +2567,7 @@ static inline TCGReg tcg_regset_first(TCGRegSet d)
#define ne_fprintf(...) \
({ int ret_ = fprintf(__VA_ARGS__); ret_ >= 0 ? ret_ : 0; })
-static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
+void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
{
char buf[128];
TCGOp *op;
@@ -2713,6 +2723,24 @@ static void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
i = k = 1;
}
break;
+#ifdef CONFIG_PLUGIN
+ case INDEX_op_plugin_cb:
+ {
+ TCGArg from = op->args[k++];
+ const char *name = NULL;
+
+ if (from < ARRAY_SIZE(plugin_from_name)) {
+ name = plugin_from_name[from];
+ }
+ if (name) {
+ col += ne_fprintf(f, "%s", name);
+ } else {
+ col += ne_fprintf(f, "$0x%" TCG_PRIlx, from);
+ }
+ i = 1;
+ }
+ break;
+#endif
default:
i = 0;
break;
diff --git a/tcg/tci.c b/tcg/tci.c
index 39adcb7d82..3afb223528 100644
--- a/tcg/tci.c
+++ b/tcg/tci.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "tcg/tcg.h"
+#include "tcg/helper-info.h"
#include "tcg/tcg-ldst.h"
#include <ffi.h>
diff --git a/util/log.c b/util/log.c
index d36c98da0b..6219819855 100644
--- a/util/log.c
+++ b/util/log.c
@@ -466,6 +466,10 @@ const QEMULogItem qemu_log_items[] = {
"show micro ops after optimization" },
{ CPU_LOG_TB_OP_IND, "op_ind",
"show micro ops before indirect lowering" },
+#ifdef CONFIG_PLUGIN
+ { LOG_TB_OP_PLUGIN, "op_plugin",
+ "show micro ops before plugin injection" },
+#endif
{ CPU_LOG_INT, "int",
"show interrupts/exceptions in short format" },
{ CPU_LOG_EXEC, "exec",