From patchwork Mon Jan 22 14:56:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Alex_Benn=C3=A9e?= X-Patchwork-Id: 764660 Delivered-To: patch@linaro.org Received: by 2002:a05:6000:10c4:b0:337:62d3:c6d5 with SMTP id b4csp1144657wrx; Mon, 22 Jan 2024 07:04:20 -0800 (PST) X-Google-Smtp-Source: AGHT+IGL8yDQpUqP/Li36XYhRQNZiW9DEypDE2zOA9agSQvGCbiO7bXlp8r4qxtfHlY19q5KduGj X-Received: by 2002:a05:622a:193:b0:42a:3996:77b9 with SMTP id s19-20020a05622a019300b0042a399677b9mr3331359qtw.4.1705935860513; Mon, 22 Jan 2024 07:04:20 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1705935860; cv=none; d=google.com; s=arc-20160816; b=HbdNUYIiST8j/e1HNm6pfScaAqkuSMu8fbsT74mE0TgI5zriHvMa7RwLRtsurCcg0h i0Yf3Gk0IZ+nPcfY44Laoe8UlLdb5DXLGRQhW1ieeyfbAmdt6/YiJ8ZQlp///4HqTUbX 2P2rQ/tgGFCps2/kM5PwhdKn6/FC9xSJC/zEDG56o0peSvSNvDEen2VMjl5LKtc9lAfn NbNxvw8LR1HgdWbvl7IEsaUVMwyTlV1lJ4+BmMSBOkWXh8/816fCTkkl4c+jZkM7gn6F THBT/wn0Rc+K8jIAUWn548yt0C6OdQqJ409prynqIM+yDIbPix6/ZNJU3WKvloNQt287 qs2w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=e8oipZKgjuKV6AKvZoVOCc+ZWL62v1Dsdc78FADqbyU=; fh=mGQIuaf4A7RZOxcauYqguCwKMqzWt70hd4nAkQm0M6A=; b=KKMa7WLzQuGFc6k7KAyx1yPZwn9riFzWu3pLBwXALaPszFYoRKK/BJjIdrO3SaQI2W 3bELfOYmE3rsKXcJslY9KdLX4CK+ZwBh4Qtl3WwT5tImNHTbQfYL5PHMz8H83AyAjnG0 DvzIY+iJC1icCkxItc8+HqjXnQ4uwZ0OVQpwDdmaVxFQeKwSxl41AAtkQ9cOxb/thIs3 1t59O+WCYJFxCryJqgiKG9QVx/WlW+oZV0Jxg9aT7bDywFpwVFa14YbpRfIWAxENqqPr 37fXdIX0tGLFg5I6ZY2wdBNIzDt8uYLu9trfPGXp/PhQKy1v9vv/jSP8542Z09ryPQr3 YkQw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b="eNzW19/0"; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id v31-20020a05622a189f00b0042a283a1a80si5841695qtc.558.2024.01.22.07.04.20 for (version=TLS1_2 cipher=ECDHE-ECDSA-CHACHA20-POLY1305 bits=256/256); Mon, 22 Jan 2024 07:04:20 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b="eNzW19/0"; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rRvo1-000820-L1; Mon, 22 Jan 2024 10:01:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rRvnt-0007ZN-Jw for qemu-devel@nongnu.org; Mon, 22 Jan 2024 10:01:37 -0500 Received: from mail-wm1-x332.google.com ([2a00:1450:4864:20::332]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rRvnn-0001lU-12 for qemu-devel@nongnu.org; Mon, 22 Jan 2024 10:01:37 -0500 Received: by mail-wm1-x332.google.com with SMTP id 5b1f17b1804b1-40e76626170so37372385e9.2 for ; Mon, 22 Jan 2024 07:01:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1705935688; x=1706540488; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=e8oipZKgjuKV6AKvZoVOCc+ZWL62v1Dsdc78FADqbyU=; b=eNzW19/0JMDznSl7ok196acmArqFrwmf23uYV7B24dPMCQYIbaBsQnMS8E3zx9sDdT qqN5UFk6QPrrVsfAEPurbvkuR3UWF9OrXygDQloEOxCw5y/86/LpPJyt4qcM3fz9BJui mtgKGJAW+GqQMSzPKo0qpd1EjbnqfUAXAgWU5/Gtg+Bx0cHiuzJ5Xu/7DuPUn0n7wUaY ZKWf1A5E6NeYGO+W5J95C/z5/oD/xI9RhVsjsS2fIYAQcmLVaQb8V782SwlLqXjzCpre I2eCbh1txoTn7PUj8VhxBlMAklkpdyffvjlBRSLl/ge7xJBf4TdvS9K7v28MhmZsFRQu n4VQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1705935688; x=1706540488; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=e8oipZKgjuKV6AKvZoVOCc+ZWL62v1Dsdc78FADqbyU=; b=fCTpruN5PWeJmys4KJufcnS1lmbngSha1eIfeyGUUwi39RmbAzklZIQx1hBz6Kz60R 8tmTezQt1N/MfM7gpQEMn3jSNqrot1oT6zpbyWZSVY+NUU0OYwbeTkIcQh/gGTHPKbse WqwFqkMfhcsGlzpoZ6stSj0w9tLNVmRG4jIbbalqykpwwDd22BrWgdOIeqZ1HEUZYC4o e85i0Xu3oen6Z8PgH+66r8A3cS2dvlz6oSB2asveJ3LuIYMpXbqDxOkP7nXjQHfs0xeS VcC64M6tJphZWML56FVM+Nz/VqGz5mRC3H/44CrZvCTtzb2JqXLSheyOEFYlsRWUaCdV 4VHQ== X-Gm-Message-State: AOJu0Ywa04sPf+UgoWhBkjmHPQgm4g84/FNq58ZtC8SNkV12jghNam8o JtpaSE1mRopGYzJefDaig2Dr9zozBq+2TwOb2ToXpTXwKE63SaNm25Twl09Bl3Q= X-Received: by 2002:a05:600c:21da:b0:40e:6f8b:b31c with SMTP id x26-20020a05600c21da00b0040e6f8bb31cmr2496907wmj.150.1705935688143; Mon, 22 Jan 2024 07:01:28 -0800 (PST) Received: from draig.lan ([85.9.250.243]) by smtp.gmail.com with ESMTPSA id d12-20020adfe88c000000b00337be3b02aasm14060919wrm.100.2024.01.22.07.01.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Jan 2024 07:01:27 -0800 (PST) Received: from draig.lan (localhost [IPv6:::1]) by draig.lan (Postfix) with ESMTP id C8B0D5F9D1; Mon, 22 Jan 2024 14:56:12 +0000 (GMT) From: =?utf-8?q?Alex_Benn=C3=A9e?= To: qemu-devel@nongnu.org Cc: Marcel Apfelbaum , "Edgar E. Iglesias" , =?utf-8?q?Philippe_Mathieu-?= =?utf-8?q?Daud=C3=A9?= , Michael Rolnik , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , Laurent Vivier , kvm@vger.kernel.org, Yoshinori Sato , Pierrick Bouvier , Palmer Dabbelt , Liu Zhiwei , Laurent Vivier , Yanan Wang , qemu-ppc@nongnu.org, Weiwei Li , qemu-s390x@nongnu.org, =?utf-8?q?Alex_Benn=C3=A9e?= , =?utf-8?q?C=C3=A9dri?= =?utf-8?q?c_Le_Goater?= , Peter Maydell , Alexandre Iooss , John Snow , Mahmoud Mandour , Wainer dos Santos Moschetta , Richard Henderson , Ilya Leoshkevich , Alistair Francis , David Woodhouse , Cleber Rosa , Beraldo Leal , Bin Meng , Nicholas Piggin , Aurelien Jarno , Daniel Henrique Barboza , Daniel Henrique Barboza , Thomas Huth , David Hildenbrand , qemu-riscv@nongnu.org, qemu-arm@nongnu.org, Paolo Bonzini , Song Gao , Eduardo Habkost , Brian Cain , Paul Durrant , Akihiko Odaki Subject: [PATCH v3 17/21] plugins: add an API to read registers Date: Mon, 22 Jan 2024 14:56:06 +0000 Message-Id: <20240122145610.413836-18-alex.bennee@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240122145610.413836-1-alex.bennee@linaro.org> References: <20240122145610.413836-1-alex.bennee@linaro.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::332; envelope-from=alex.bennee@linaro.org; helo=mail-wm1-x332.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: qemu-devel-bounces+patch=linaro.org@nongnu.org We can only request a list of registers once the vCPU has been initialised so the user needs to use either call the get function on vCPU initialisation or during the translation phase. We don't expose the reg number to the plugin instead hiding it behind an opaque handle. This allows for a bit of future proofing should the internals need to be changed while also being hashed against the CPUClass so we can handle different register sets per-vCPU in hetrogenous situations. Having an internal state within the plugins also allows us to expand the interface in future (for example providing callbacks on register change if the translator can track changes). Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1706 Cc: Akihiko Odaki Message-Id: <20240103173349.398526-39-alex.bennee@linaro.org> Based-on: <20231025093128.33116-18-akihiko.odaki@daynix.com> Signed-off-by: Alex BennĂ©e Reviewed-by: Pierrick Bouvier --- include/qemu/qemu-plugin.h | 51 +++++++++++++++- plugins/api.c | 111 +++++++++++++++++++++++++++++++++++ plugins/qemu-plugins.symbols | 2 + 3 files changed, 162 insertions(+), 2 deletions(-) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 4daab6efd29..2c1930e7e45 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -11,6 +11,7 @@ #ifndef QEMU_QEMU_PLUGIN_H #define QEMU_QEMU_PLUGIN_H +#include #include #include #include @@ -227,8 +228,8 @@ struct qemu_plugin_insn; * @QEMU_PLUGIN_CB_R_REGS: callback reads the CPU's regs * @QEMU_PLUGIN_CB_RW_REGS: callback reads and writes the CPU's regs * - * Note: currently unused, plugins cannot read or change system - * register state. + * Note: currently QEMU_PLUGIN_CB_RW_REGS is unused, plugins cannot change + * system register state. */ enum qemu_plugin_cb_flags { QEMU_PLUGIN_CB_NO_REGS, @@ -708,4 +709,50 @@ uint64_t qemu_plugin_end_code(void); QEMU_PLUGIN_API uint64_t qemu_plugin_entry_code(void); +/** struct qemu_plugin_register - Opaque handle for register access */ +struct qemu_plugin_register; + +/** + * typedef qemu_plugin_reg_descriptor - register descriptions + * + * @handle: opaque handle for retrieving value with qemu_plugin_read_register + * @name: register name + * @feature: optional feature descriptor, can be NULL + */ +typedef struct { + struct qemu_plugin_register *handle; + const char *name; + const char *feature; +} qemu_plugin_reg_descriptor; + +/** + * qemu_plugin_get_registers() - return register list for vCPU + * @vcpu_index: vcpu to query + * + * Returns a GArray of qemu_plugin_reg_descriptor or NULL. Caller + * frees the array (but not the const strings). + * + * Should be used from a qemu_plugin_register_vcpu_init_cb() callback + * after the vCPU is initialised. + */ +GArray *qemu_plugin_get_registers(unsigned int vcpu_index); + +/** + * qemu_plugin_read_register() - read register + * + * @vcpu: vcpu index + * @handle: a @qemu_plugin_reg_handle handle + * @buf: A GByteArray for the data owned by the plugin + * + * This function is only available in a context that register read access is + * explicitly requested. + * + * Returns the size of the read register. The content of @buf is in target byte + * order. On failure returns -1 + */ +int qemu_plugin_read_register(unsigned int vcpu, + struct qemu_plugin_register *handle, + GByteArray *buf); + + #endif /* QEMU_QEMU_PLUGIN_H */ diff --git a/plugins/api.c b/plugins/api.c index ac39cdea0b3..8d5cca53295 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -8,6 +8,7 @@ * * qemu_plugin_tb * qemu_plugin_insn + * qemu_plugin_register * * Which can then be passed back into the API to do additional things. * As such all the public functions in here are exported in @@ -35,10 +36,12 @@ */ #include "qemu/osdep.h" +#include "qemu/main-loop.h" #include "qemu/plugin.h" #include "qemu/log.h" #include "tcg/tcg.h" #include "exec/exec-all.h" +#include "exec/gdbstub.h" #include "exec/ram_addr.h" #include "disas/disas.h" #include "plugin.h" @@ -435,3 +438,111 @@ uint64_t qemu_plugin_entry_code(void) #endif return entry; } + +/* + * Register handles + * + * The plugin infrastructure keeps hold of these internal data + * structures which are presented to plugins as opaque handles. They + * are global to the system and therefor additions to the hash table + * must be protected by the @reg_handle_lock. + * + * In order to future proof for up-coming heterogeneous work we want + * different entries for each CPU type while sharing them in the + * common case of multiple cores of the same type. + */ + +static QemuMutex reg_handle_lock; + +struct qemu_plugin_register { + const char *name; + int gdb_reg_num; +}; + +static GHashTable *reg_handles; /* hash table of PluginReg */ + +/* Generate a stable key - would xxhash be overkill? */ +static gpointer cpu_plus_reg_to_key(CPUState *cs, int gdb_regnum) +{ + uintptr_t key = (uintptr_t) cs->cc; + key ^= gdb_regnum; + return GUINT_TO_POINTER(key); +} + +/* + * Create register handles. + * + * We need to create a handle for each register so the plugin + * infrastructure can call gdbstub to read a register. We also + * construct a result array with those handles and some ancillary data + * the plugin might find useful. + */ + +static GArray *create_register_handles(CPUState *cs, GArray *gdbstub_regs) +{ + GArray *find_data = g_array_new(true, true, + sizeof(qemu_plugin_reg_descriptor)); + + WITH_QEMU_LOCK_GUARD(®_handle_lock) { + + if (!reg_handles) { + reg_handles = g_hash_table_new(g_direct_hash, g_direct_equal); + } + + for (int i = 0; i < gdbstub_regs->len; i++) { + GDBRegDesc *grd = &g_array_index(gdbstub_regs, GDBRegDesc, i); + gpointer key = cpu_plus_reg_to_key(cs, grd->gdb_reg); + struct qemu_plugin_register *val = g_hash_table_lookup(reg_handles, + key); + + /* skip "un-named" regs */ + if (!grd->name) { + continue; + } + + /* Doesn't exist, create one */ + if (!val) { + val = g_new0(struct qemu_plugin_register, 1); + val->gdb_reg_num = grd->gdb_reg; + val->name = g_intern_string(grd->name); + + g_hash_table_insert(reg_handles, key, val); + } + + /* Create a record for the plugin */ + qemu_plugin_reg_descriptor desc = { + .handle = val, + .name = val->name, + .feature = g_intern_string(grd->feature_name) + }; + g_array_append_val(find_data, desc); + } + } + + return find_data; +} + +GArray *qemu_plugin_get_registers(unsigned int vcpu) +{ + CPUState *cs = qemu_get_cpu(vcpu); + if (cs) { + g_autoptr(GArray) regs = gdb_get_register_list(cs); + return regs->len ? create_register_handles(cs, regs) : NULL; + } else { + return NULL; + } +} + +int qemu_plugin_read_register(unsigned int vcpu, + struct qemu_plugin_register *reg, GByteArray *buf) +{ + CPUState *cs = qemu_get_cpu(vcpu); + /* assert with debugging on? */ + return gdb_read_register(cs, buf, reg->gdb_reg_num); +} + +static void __attribute__((__constructor__)) qemu_api_init(void) +{ + qemu_mutex_init(®_handle_lock); + +} diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols index 71f6c90549d..6963585c1ea 100644 --- a/plugins/qemu-plugins.symbols +++ b/plugins/qemu-plugins.symbols @@ -3,6 +3,7 @@ qemu_plugin_end_code; qemu_plugin_entry_code; qemu_plugin_get_hwaddr; + qemu_plugin_get_registers; qemu_plugin_hwaddr_device_name; qemu_plugin_hwaddr_is_io; qemu_plugin_hwaddr_phys_addr; @@ -20,6 +21,7 @@ qemu_plugin_n_vcpus; qemu_plugin_outs; qemu_plugin_path_to_binary; + qemu_plugin_read_register; qemu_plugin_register_atexit_cb; qemu_plugin_register_flush_cb; qemu_plugin_register_vcpu_exit_cb;