From nobody Thu Nov 6 10:38:32 2025 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=temperror (zoho.com: Error in retrieving data from DNS) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1540489070341150.59129927341326; Thu, 25 Oct 2018 10:37:50 -0700 (PDT) Received: from localhost ([::1]:56094 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gFjZj-0004Vc-2o for importer@patchew.org; Thu, 25 Oct 2018 13:37:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40419) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gFjKl-0006hz-6y for qemu-devel@nongnu.org; Thu, 25 Oct 2018 13:22:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gFjKH-00007P-Ar for qemu-devel@nongnu.org; Thu, 25 Oct 2018 13:21:44 -0400 Received: from out3-smtp.messagingengine.com ([66.111.4.27]:58817) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gFjKF-0008Qf-Rg for qemu-devel@nongnu.org; Thu, 25 Oct 2018 13:21:41 -0400 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 20826221CC; Thu, 25 Oct 2018 13:21:11 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Thu, 25 Oct 2018 13:21:11 -0400 Received: from localhost (flamenco.cs.columbia.edu [128.59.20.216]) by mail.messagingengine.com (Postfix) with ESMTPA id 959BBE47CB; Thu, 25 Oct 2018 13:21:10 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=braap.org; h= from:to:cc:subject:date:message-id:in-reply-to:references; s= mesmtp; bh=nHNZGKhfVZ4jUtv2dSbuFnbN8wa/CiobFD05+W8f8Zg=; b=R3V2e mqVpQ1uCYOfK8MxxdzWva8O60nYZ2B3BoqWJXqPJW5vFi/3gsNSz870kysouzojq 5UJvDH51d2BdSuOyBhfYAri7z5Y40UHyx7kKtC/q8t1+ef9NY7osWyWRnMOORzvo NcknC1QNaXh0qYBJ5WbqXtA33i+FrixXJ038nE= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:date:from:in-reply-to:message-id :references:subject:to:x-me-proxy:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; bh=nHNZGKhfVZ4jUtv2dSbuFnbN8wa/C iobFD05+W8f8Zg=; b=lyQZoHWCksVtHvfMXQrcqv93o17SYaruSlYA1+8bWLF64 82WgT71F+Gch3x7q8Tl8F1ZDFg/9wkWgx4kX4l1HXuz1eUCpaRnC/J6vb/dz/MzZ SM29/lK4QPX410eTfoCk7ou4ctNDIXkMPuzk5UJAPlFX1lu8kRc0MZNU/pCNz6yz oJg82KCccFY1VMpl083Mx09DFJCf7SX6QIOCgIf8rcLJ9jsTZJyTw0/Y4fjfbFgU sYnLevnFemYRvesqigICQ/Tx9xa5TjrZBECphjn/+lHG1Kexjg4zWxEfLfiFbCCE /5Rl3OEKhI9FNTIoJ/xMa2aXEPIlZn4bL6wJZ1GNw== X-ME-Sender: X-ME-Proxy: From: "Emilio G. Cota" To: qemu-devel@nongnu.org Date: Thu, 25 Oct 2018 13:20:26 -0400 Message-Id: <20181025172057.20414-18-cota@braap.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181025172057.20414-1-cota@braap.org> References: <20181025172057.20414-1-cota@braap.org> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.111.4.27 Subject: [Qemu-devel] [RFC 17/48] plugin-gen: add TCG code generation helpers X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , =?UTF-8?q?Alex=20Benn=C3=A9e?= , =?UTF-8?q?Llu=C3=ADs=20Vilanova?= , Pavel Dovgalyuk , Stefan Hajnoczi Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Here we implement several features: - Inlining TCG code for simple operations. Crucially, we do not export TCG ops to plugins. Instead, we give them a C API to insert inlined ops. So far we only support adding an immediate to a u64, e.g. to count events. - "Direct" callbacks. These are callbacks that do not go via a helper. Instead, the helper is defined at run-time, so that the plugin code is directly called from TCG. This makes direct callbacks as efficient as possible; they are therefore used for very frequent events, e.g. memory callbacks. - Passing the host address to memory callbacks. Most of this is implemented in a later patch though. - Instrumentation of memory accesses performed from helpers. See comment. Signed-off-by: Emilio G. Cota --- include/exec/plugin-gen.h | 51 +++++++++ accel/tcg/plugin-gen.c | 230 ++++++++++++++++++++++++++++++++++++++ accel/tcg/Makefile.objs | 1 + 3 files changed, 282 insertions(+) create mode 100644 include/exec/plugin-gen.h create mode 100644 accel/tcg/plugin-gen.c diff --git a/include/exec/plugin-gen.h b/include/exec/plugin-gen.h new file mode 100644 index 0000000000..46a167527e --- /dev/null +++ b/include/exec/plugin-gen.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017, Emilio G. Cota + * + * License: GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * plugin-gen.h - TCG-dependent definitions for generating plugin code + * + * This header should be included only from plugin.c and C files that emit + * TCG code. + */ +#ifndef QEMU_PLUGIN_GEN_H +#define QEMU_PLUGIN_GEN_H + +#include "qemu/plugin.h" +#include "tcg/tcg.h" + +#ifdef CONFIG_PLUGINS + +void qemu_plugin_gen_vcpu_mem_callbacks(struct qemu_plugin_dyn_cb_arr *arr, + TCGv vaddr, uint8_t info); + +void qemu_plugin_gen_vcpu_udata_callbacks(struct qemu_plugin_dyn_cb_arr *a= rr); + +void qemu_plugin_gen_disable_mem_helpers(void); + +void +qemu_plugin_gen_enable_mem_helpers(const struct qemu_plugin_dyn_cb_arr *or= ig); + +#else /* !CONFIG_PLUGINS */ + +static inline void +qemu_plugin_gen_vcpu_mem_callbacks(struct qemu_plugin_dyn_cb_arr *arr, + TCGv vaddr, uint8_t info) +{ } + +static inline void +qemu_plugin_gen_vcpu_udata_callbacks(struct qemu_plugin_dyn_cb_arr *arr) +{ } + +static inline void qemu_plugin_gen_disable_mem_helpers(void) +{ } + +static inline void +qemu_plugin_gen_enable_mem_helpers(const struct qemu_plugin_dyn_cb_arr *or= ig) +{ } + +#endif /* CONFIG_PLUGINS */ + +#endif /* QEMU_PLUGIN_GEN_H */ + diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c new file mode 100644 index 0000000000..75f182be37 --- /dev/null +++ b/accel/tcg/plugin-gen.c @@ -0,0 +1,230 @@ +#include "qemu/osdep.h" +#include "cpu.h" +#include "tcg/tcg.h" +#include "tcg/tcg-op.h" +#include "exec/exec-all.h" +#include "exec/plugin-gen.h" + +static void gen_inline_op(struct qemu_plugin_dyn_cb *cb) +{ + TCGv_i64 val =3D tcg_temp_new_i64(); + TCGv_ptr ptr =3D tcg_const_ptr(cb->userp); + + tcg_gen_ld_i64(val, ptr, 0); + switch (cb->inline_insn.op) { + case QEMU_PLUGIN_INLINE_ADD_U64: + tcg_gen_addi_i64(val, val, cb->inline_insn.imm); + break; + default: + g_assert_not_reached(); + } + tcg_gen_st_i64(val, ptr, 0); + + tcg_temp_free_ptr(ptr); + tcg_temp_free_i64(val); +} + +static void gen_helper_mem_cb(const char *name, unsigned flags, + qemu_plugin_vcpu_mem_cb_t cb, TCGv_i32 cpu_i= ndex, + TCGv_i32 meminfo, TCGv_i64 vaddr, TCGv_ptr u= data) +{ + TCGHelperInfo info =3D { + .func =3D cb, + .name =3D name, + .flags =3D flags, + .sizemask =3D dh_sizemask(void, 0) | + dh_sizemask(i32, 1) | + dh_sizemask(i32, 2) | + dh_sizemask(i64, 3) | + dh_sizemask(ptr, 4), + + }; + TCGTemp *args[] =3D { + tcgv_i32_temp(cpu_index), + tcgv_i32_temp(meminfo), + tcgv_i64_temp(vaddr), + tcgv_ptr_temp(udata), + }; + + tcg_gen_runtime_helper(&info, NULL, ARRAY_SIZE(args), args); +} + +static void gen_helper_mem_haddr_cb(const char *name, unsigned flags, + qemu_plugin_vcpu_mem_haddr_cb_t cb, + TCGv_i32 cpu_index, TCGv_i32 meminfo, + TCGv_i64 vaddr, TCGv_ptr haddr, + TCGv_ptr udata) +{ + TCGHelperInfo info =3D { + .func =3D cb, + .name =3D name, + .flags =3D flags, + .sizemask =3D dh_sizemask(void, 0) | + dh_sizemask(i32, 1) | + dh_sizemask(i32, 2) | + dh_sizemask(i64, 3) | + dh_sizemask(ptr, 4) | + dh_sizemask(ptr, 5), + + }; + TCGTemp *args[] =3D { + tcgv_i32_temp(cpu_index), + tcgv_i32_temp(meminfo), + tcgv_i64_temp(vaddr), + tcgv_ptr_temp(haddr), + tcgv_ptr_temp(udata), + }; + + tcg_gen_runtime_helper(&info, NULL, ARRAY_SIZE(args), args); +} + +static void gen_mem_cb(struct qemu_plugin_dyn_cb *cb, TCGv vaddr, uint8_t = info) +{ + TCGv_i32 cpu_index =3D tcg_temp_new_i32(); + TCGv_i32 meminfo =3D tcg_const_i32(info); + TCGv_i64 vaddr64 =3D tcg_temp_new_i64(); + TCGv_ptr udata =3D tcg_const_ptr(cb->userp); + TCGv_ptr haddr; + + tcg_gen_ld_i32(cpu_index, cpu_env, + -ENV_OFFSET + offsetof(CPUState, cpu_index)); + tcg_gen_extu_tl_i64(vaddr64, vaddr); + + if (cb->mem.haddr) { +#ifdef CONFIG_SOFTMMU + haddr =3D tcg_temp_new_ptr(); + tcg_gen_ld_ptr(haddr, cpu_env, offsetof(CPUArchState, hostaddr)); +#else + haddr =3D tcg_const_ptr(NULL); +#endif + gen_helper_mem_haddr_cb("helper_plugin_vcpu_mem_haddr_cb", + cb->tcg_flags, cb->f.vcpu_mem_haddr, + cpu_index, meminfo, vaddr64, haddr, udata); + tcg_temp_free_ptr(haddr); + } else { + gen_helper_mem_cb("helper_plugin_vcpu_mem_cb", cb->tcg_flags, + cb->f.vcpu_mem, cpu_index, meminfo, vaddr64, + udata); + } + + tcg_temp_free_ptr(udata); + tcg_temp_free_i64(vaddr64); + tcg_temp_free_i32(meminfo); + tcg_temp_free_i32(cpu_index); +} + +void qemu_plugin_gen_vcpu_mem_callbacks(struct qemu_plugin_dyn_cb_arr *arr, + TCGv vaddr, uint8_t info) +{ + size_t i; + + for (i =3D 0; i < arr->n; i++) { + struct qemu_plugin_dyn_cb *cb =3D &arr->data[i]; + + switch (cb->type) { + case QEMU_PLUGIN_DYN_CB_TYPE_REGULAR: + gen_mem_cb(cb, vaddr, info); + break; + case QEMU_PLUGIN_DYN_CB_TYPE_INLINE: + gen_inline_op(cb); + break; + default: + g_assert_not_reached(); + } + } +} + +static void gen_helper_vcpu_udata_cb(const char *name, unsigned flags, + qemu_plugin_vcpu_udata_cb_t cb, + TCGv_i32 cpu_index, TCGv_ptr udata) +{ + TCGHelperInfo info =3D { + .func =3D cb, + .name =3D name, + .flags =3D flags, + .sizemask =3D dh_sizemask(void, 0) | + dh_sizemask(i32, 1) | + dh_sizemask(ptr, 2), + }; + TCGTemp *args[] =3D { + tcgv_i32_temp(cpu_index), + tcgv_ptr_temp(udata), + }; + + tcg_gen_runtime_helper(&info, NULL, ARRAY_SIZE(args), args); +} + +static void gen_vcpu_udata_cb(struct qemu_plugin_dyn_cb *cb) +{ + TCGv_i32 cpu_index =3D tcg_temp_new_i32(); + TCGv_ptr udata =3D tcg_const_ptr(cb->userp); + + tcg_gen_ld_i32(cpu_index, cpu_env, + -ENV_OFFSET + offsetof(CPUState, cpu_index)); + + gen_helper_vcpu_udata_cb("helper_plugin_vcpu_udata_cb", cb->tcg_flags, + cb->f.vcpu_udata, cpu_index, udata); + + tcg_temp_free_ptr(udata); + tcg_temp_free_i32(cpu_index); +} + +void qemu_plugin_gen_vcpu_udata_callbacks(struct qemu_plugin_dyn_cb_arr *a= rr) +{ + size_t i; + + for (i =3D 0; i < arr->n; i++) { + struct qemu_plugin_dyn_cb *cb =3D &arr->data[i]; + + switch (cb->type) { + case QEMU_PLUGIN_DYN_CB_TYPE_REGULAR: + gen_vcpu_udata_cb(cb); + break; + case QEMU_PLUGIN_DYN_CB_TYPE_INLINE: + gen_inline_op(cb); + break; + default: + g_assert_not_reached(); + } + } +} + +/* + * Tracking memory accesses performed from helpers requires extra work. + * If an instruction is emulated with helpers, struct qemu_plugin_insn's + * .calls_helpers is set. If so, this function is called. Here we do two + * things: (1) copy the CB descriptor, and keep track of it so that it can= be + * freed later on, and (2) point CPUState.plugin_mem_cbs to the descriptor= , so + * that we can read it at run-time (i.e. when the helper executes). + * This run-time access is performed from qemu_plugin_vcpu_mem_cb. + * + * Note that qemu_plugin_gen_disable_mem_helpers undoes (2). + */ +void +qemu_plugin_gen_enable_mem_helpers(const struct qemu_plugin_dyn_cb_arr *or= ig) +{ + struct qemu_plugin_dyn_cb_arr *arr; + TCGv_ptr ptr; + + arr =3D g_new(struct qemu_plugin_dyn_cb_arr, 1); + arr->capacity =3D orig->n; + arr->n =3D orig->n; + arr->data =3D g_new(struct qemu_plugin_dyn_cb, arr->n); + memcpy(arr->data, orig->data, sizeof(*arr->data) * arr->n); + qemu_plugin_add_dyn_cb_arr(arr); + + ptr =3D tcg_const_ptr(arr); + tcg_gen_st_ptr(ptr, cpu_env, -ENV_OFFSET + offsetof(CPUState, + plugin_mem_cbs)); + tcg_temp_free_ptr(ptr); +} + +/* Called once we're done instrumenting an instruction that calls helpers = */ +void qemu_plugin_gen_disable_mem_helpers(void) +{ + TCGv_ptr ptr =3D tcg_const_ptr(NULL); + + tcg_gen_st_ptr(ptr, cpu_env, -ENV_OFFSET + offsetof(CPUState, + plugin_mem_cbs)); + tcg_temp_free_ptr(ptr); +} diff --git a/accel/tcg/Makefile.objs b/accel/tcg/Makefile.objs index d381a02f34..4f617e4fe5 100644 --- a/accel/tcg/Makefile.objs +++ b/accel/tcg/Makefile.objs @@ -6,3 +6,4 @@ obj-y +=3D translator.o =20 obj-$(CONFIG_USER_ONLY) +=3D user-exec.o obj-$(call lnot,$(CONFIG_SOFTMMU)) +=3D user-exec-stub.o +obj-$(CONFIG_PLUGINS) +=3D plugin-gen.o --=20 2.17.1