From nobody Sun Feb 8 23:32:15 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1749498003; cv=none; d=zohomail.com; s=zohoarc; b=jwTBc3A8MQDTaKZxEGxWdssu1jbMxwyYmtbPlPq9GL/2W44a06lzMzBft8Oc7HJPc9qFWbyiwc/a219H9QJ6lbVDRkI3Ra4wnffe2wFa05k699Uwv78QJR7x8apIeuYFL1tq41AUGYQjoR915jbDZsg8sbrD/IFdlDbW0jA9o3c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749498003; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=1ysiNB3jN3pm4xSzw9lWbP2QG1HmR4QbzZmy+B07iUo=; b=JrEvSqhO/0Ufspqk+pLT3eVmCN3/miRx1Bv4hk1msja33blCEI+m0AvzOCG0M04LIpLqhYoXS0BmBd53uJvciYWCiW8KVD7WhokKPZjZ18/6EZ6fMFATbR+7bawK1suFORSkt7UsMLTJN9PnZw/X/F8+C8kJA3kG2szpDFA7TVM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749498003306337.540681327524; Mon, 9 Jun 2025 12:40:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOiKZ-0007Do-81; Mon, 09 Jun 2025 15:38:51 -0400 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 1uOiKU-0007CA-RE for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:46 -0400 Received: from mail-pf1-x432.google.com ([2607:f8b0:4864:20::432]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uOiKT-0004Cx-6y for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:46 -0400 Received: by mail-pf1-x432.google.com with SMTP id d2e1a72fcca58-742caef5896so3874608b3a.3 for ; Mon, 09 Jun 2025 12:38:44 -0700 (PDT) Received: from shemhazi.lan ([50.46.174.34]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7482b083b03sm6095725b3a.83.2025.06.09.12.38.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 12:38:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749497923; x=1750102723; 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=1ysiNB3jN3pm4xSzw9lWbP2QG1HmR4QbzZmy+B07iUo=; b=dnOI/VgJHQsi/iDeTvZlhtR8ZUE7ry/+2W+tHaqDHk4aDYVWwbT+wDajqJoWt7MkQe 7f3ZVWVsSRr7cT75Fnig0krIfHR6RriiClBgWsmpxBsStZnfV8VsBYH2MjQOD/15Qwpw KYTeHgMZVo7UEci64iSMpE9/JLXRgn0ztqmiM/ru+6fu/T7cXoiAOLgKyt0X1wfhMkVL VbKmNrSRcWIhmxs3uHBER5OFO8Yh9AjZMgDqna1S/3aUk2k1mGz+oydtNf3rTMUL9tvW lzn0tyEyJrJyufPlXq6xJFxpJvDUckSb7akJAXwppruypmwGluADkqgDQAdMQPFKYWnJ VVbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749497923; x=1750102723; 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=1ysiNB3jN3pm4xSzw9lWbP2QG1HmR4QbzZmy+B07iUo=; b=Ea1nQgMbQaert4cvgj1BLEa0IlVv08Ox8SKOZ4RfqEa8fnvk5ogT0BKHMjBOtH+QW9 zfepQQaZscMrizgDTYhEwaMEMZ0TKecA7SFRFPgEBnOJNUaYF6+5lmix6xoi9ka3d15y cni4yJpVQByeWAgEuhIBZulFwYDAA3Lw5jZ4HhLB3AR4SJt1+26IuAg3p025kF5z8cRZ 3otxZHM7aW+nojyymJ9C+CIMjBp7vVbJnI2n0eq3gf88h8vDxikXkN3OaXLU6v9+Z/eJ CnUaDvdJJlSV3YB6c80H7jAQ56lg4r0a7oZkmQhyGpY6kxSpNTlfXTTwpcD5v8NR7EqK 1TbQ== X-Gm-Message-State: AOJu0YxNwSbawRRU8DfDCsjJKgUykG6tePaklC97jxz8hpWcAJTOX4VL b0nkHkGBQ4HORntQqVjb1sBIz566S/aOwz9icDreythA1VVI5Y81/77CEtS4URNJ X-Gm-Gg: ASbGncuPZLooh7eE1DGndCL4MN4P6mUaEIZago+1N6xqKzAkqa1LqzPddf0mqiHPSQD 4naeytFCBbKllNN6hny7rne/WfYUIaZoi2JMEnFQySRNfInR+ag1By1T7p0FI3MUD/+C+43xZuQ hqUYgKbreC8W3oTV4BpeG57G0vgnS6S3oIfe0V3UdNrIxKqmi8BnbysCctvsV4pzUjiK7K34384 lO0LEJ5Vz1YiLGDEIhG7g5sBfYyKt+78XSMdEhzXmmWpzdNbKvYYDumCedSTgAfUeKjI0GxhoH7 DDFyaHa9KgZHkXIr3ULwMR6ZhYQNmeA9Ej4LgyUEQA8oDbTbn1k= X-Google-Smtp-Source: AGHT+IEu2vviCFSVWJZumGKQPmcucedY4J0g/Tj0dxm9S+iDdYQnSQEyZDo9yg4l/GXVT4Pz4nmshg== X-Received: by 2002:a05:6a00:1991:b0:748:31ed:ba8a with SMTP id d2e1a72fcca58-74831edbda7mr14787060b3a.15.1749497923096; Mon, 09 Jun 2025 12:38:43 -0700 (PDT) From: Rowan Hart To: qemu-devel@nongnu.org Cc: Zhao Liu , Eduardo Habkost , Pierrick Bouvier , Richard Henderson , Mahmoud Mandour , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Marcel Apfelbaum , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Yanan Wang , Alexandre Iooss , novafacing , Julian Ganz Subject: [PATCH v11 1/8] gdbstub: Expose gdb_write_register function to consumers of gdbstub Date: Mon, 9 Jun 2025 12:38:34 -0700 Message-ID: <20250609193841.348076-2-rowanbhart@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609193841.348076-1-rowanbhart@gmail.com> References: <20250609193841.348076-1-rowanbhart@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::432; envelope-from=rowanbhart@gmail.com; helo=mail-pf1-x432.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, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1749498005747116600 From: novafacing This patch exposes the gdb_write_register function from gdbstub/gdbstub.c via the exec/gdbstub.h header file to support use in plugins to write register contents. Reviewed-by: Alex Benn=C3=A9e Reviewed-by: Julian Ganz Reviewed-by: Pierrick Bouvier Signed-off-by: Rowan Hart --- gdbstub/gdbstub.c | 2 +- include/exec/gdbstub.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 565f6b33a9..5846e481be 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -534,7 +534,7 @@ int gdb_read_register(CPUState *cpu, GByteArray *buf, i= nt reg) return 0; } =20 -static int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) +int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg) { GDBRegisterState *r; =20 diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h index 0675b0b646..a16c0051ce 100644 --- a/include/exec/gdbstub.h +++ b/include/exec/gdbstub.h @@ -124,6 +124,20 @@ const GDBFeature *gdb_find_static_feature(const char *= xmlname); */ int gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); =20 +/** + * gdb_write_register() - Write a register associated with a CPU. + * @cpu: The CPU associated with the register. + * @buf: The buffer that the register contents will be set to. + * @reg: The register's number returned by gdb_find_feature_register(). + * + * The size of @buf must be at least the size of the register being + * written. + * + * Return: The number of written bytes, or 0 if an error occurred (for + * example, an unknown register was provided). + */ +int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg); + /** * typedef GDBRegDesc - a register description from gdbstub */ --=20 2.49.0 From nobody Sun Feb 8 23:32:15 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1749498078; cv=none; d=zohomail.com; s=zohoarc; b=BNFauBWM90lLQMvhFbk6+QWG5Njsd+EchBhfowlBchBN9X29Fl4gQjtFnrFQRb7zksgPefjBaL6AmMFeVwEngbkR3ZD4uanWcXevkTOw9JGugiaxmJ9xNPf8yks3ZdGvMAHo37COj29xCwQjc6tHEKs++fpM0HVfiZ035pgoXdg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749498078; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=DkzAOT9KPhbXdwiYkwrjtSXHJRVHCh65cjh/wF+xrzM=; b=nb2nZwLaZ16rRxVv3nAC05pIJTfro4mBHNf6WHAkZR3gPPFVnJegDDk1bQwranq5toUa2nDAz/o8InYW+CuC4Bt2RTUrqfsYYYZp1MN2UZYvZOjTzsP7+XDZu09NgdrblDv4t0SH7M/7ZabByqDZaYSvmdHTuQ1GUqpNz/W8k1s= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749498078340852.2403461134684; Mon, 9 Jun 2025 12:41:18 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOiKX-0007DR-T3; Mon, 09 Jun 2025 15:38:49 -0400 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 1uOiKW-0007Ch-FI for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:48 -0400 Received: from mail-pf1-x42f.google.com ([2607:f8b0:4864:20::42f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uOiKU-0004D2-9v for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:48 -0400 Received: by mail-pf1-x42f.google.com with SMTP id d2e1a72fcca58-73bf5aa95e7so3526781b3a.1 for ; Mon, 09 Jun 2025 12:38:45 -0700 (PDT) Received: from shemhazi.lan ([50.46.174.34]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7482b083b03sm6095725b3a.83.2025.06.09.12.38.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 12:38:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749497924; x=1750102724; 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=DkzAOT9KPhbXdwiYkwrjtSXHJRVHCh65cjh/wF+xrzM=; b=ZcD08pHw5L8TgrQ3UMNznbh7L84ATtGnART7P4wD8xDzB9koOHYb1WY/KFV02IJeLR juJT7crOWWB4eujFo5hNcZns+b/Px4hQofFYr4wn08/iZbhNpthob/yTadcbYCRVCzlL gcljIv91t+Ggkbqj++TFy/2KGgdAz2WgL7LtIU+nKrup/UfIQSG2CvFKchqVqIydzuJ8 ibR5k8YcLr/iPYIGeE58f3TEnbW4K4rEnRGuJKMA95nOFZnwfNmfX14RDDfC7Ch5wCES vJfQ6+IQua44BlNSOi4RDl3/gDHFP8SAq/dPEdH191IjfCUCGcdwub7QDxWtvbYljV5I v8HQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749497924; x=1750102724; 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=DkzAOT9KPhbXdwiYkwrjtSXHJRVHCh65cjh/wF+xrzM=; b=aE+seHjV3mbTc6hoIncmVkSP3R1HgoLeOqnHx/ehQMNMPKv7mnDViVk50M7QJibqdf l+3sX3MVsDBl8+1k3pTkBDW4DqvFJJvoptrQnUjg/icuIEF146O70W5efahT/hILJo2+ b07XxMPnaEo6mN19q5LOFH+qj23bZLZBJG1R70cZtnfaOHQViud/vSt7n93k3ei02V65 HvMJwjVJyeD5/33Omiv2AEbp0UL4YEi1EAt/mnow4L31kK/lpYDg3f7vp9QbesrLlczU YWbYeUTqXmfq5G9tsqlF/Jalrcez0QnXdWAnj/MHbTXuJossrtr/pFmgq+ctyaY8J3Rb 0HpA== X-Gm-Message-State: AOJu0YwqHO0IHsAlbWvYaTIE0shGuihaiI3RaS6qxe2L/EgT6aibJAqz v+i/cxBXbwGXJ7tD5LR/NUJXvVqEbE0qLWnPde7sV4M0bQYidFHW8qfRkxZp5CeL X-Gm-Gg: ASbGncsC4Y+7qvFWkUB30O5/aFzRk5o7t1RdfCYu6Chli/qhrOwXzuxlf2h0sfchQ7A VliUR627pgVXEkgfyvwm4JtGoaiUQx0obLRTGdJhBLMGNuYQalFgtSP9raaoYTjndUkq6/1/NdT NxJbaBKLRnP15r4SFzgk31DUKP4C/8yVI0tk5N2pnPSXUwX+/qFoIoDkLSID8UHaxkeymEeC+V1 WeQCSPN4aJqBiuaFetEAPhCPThRhMuCCS+/BulQFiMNseDsI9QrjjFDbgUFUQK2Tmxm6Sto9GVM 4UeUNJg8dbixpzML4olbnEA4VqD3p5V+0euu16/XmX5eGggeA5tsv8D8y/Z/bQ== X-Google-Smtp-Source: AGHT+IEMPqZK/MvBEesY2maPebq7AsTTyWZpgXvbF/1Z1XPbLIma9zkcJU/kGGJE9aVXKcWGO2l/qA== X-Received: by 2002:a05:6a00:22d1:b0:742:3cc1:9485 with SMTP id d2e1a72fcca58-74827e9c914mr17710660b3a.12.1749497923885; Mon, 09 Jun 2025 12:38:43 -0700 (PDT) From: Rowan Hart To: qemu-devel@nongnu.org Cc: Zhao Liu , Eduardo Habkost , Pierrick Bouvier , Richard Henderson , Mahmoud Mandour , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Marcel Apfelbaum , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Yanan Wang , Alexandre Iooss , novafacing Subject: [PATCH v11 2/8] plugins: Add register write API Date: Mon, 9 Jun 2025 12:38:35 -0700 Message-ID: <20250609193841.348076-3-rowanbhart@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609193841.348076-1-rowanbhart@gmail.com> References: <20250609193841.348076-1-rowanbhart@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::42f; envelope-from=rowanbhart@gmail.com; helo=mail-pf1-x42f.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, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1749498080578116600 Content-Type: text/plain; charset="utf-8" From: novafacing This patch adds a function to the plugins API to allow plugins to write register contents. It also moves the qemu_plugin_read_register function so all the register-related functions are grouped together in the file. Reviewed-by: Pierrick Bouvier Signed-off-by: Rowan Hart --- include/qemu/qemu-plugin.h | 54 ++++++++++++++++++++++++++------------ plugins/api.c | 26 +++++++++++++----- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 3a850aa216..cfe1692ecb 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -871,7 +871,8 @@ struct qemu_plugin_register; /** * typedef qemu_plugin_reg_descriptor - register descriptions * - * @handle: opaque handle for retrieving value with qemu_plugin_read_regis= ter + * @handle: opaque handle for retrieving value with qemu_plugin_read_regis= ter or + * writing value with qemu_plugin_write_register * @name: register name * @feature: optional feature descriptor, can be NULL */ @@ -893,6 +894,41 @@ typedef struct { QEMU_PLUGIN_API GArray *qemu_plugin_get_registers(void); =20 +/** + * qemu_plugin_read_register() - read register for current vCPU + * + * @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 via the QEMU_PLUGIN_CB_R_REGS flag. + * + * Returns the size of the read register. The content of @buf is in target= byte + * order. On failure returns -1. + */ +QEMU_PLUGIN_API +int qemu_plugin_read_register(struct qemu_plugin_register *handle, + GByteArray *buf); + +/** + * qemu_plugin_write_register() - write register for current vCPU + * + * @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 write access= is + * explicitly requested via the QEMU_PLUGIN_CB_RW_REGS flag. + * + * The size of @buf must be at least the size of the requested register. + * Attempting to write a register with @buf smaller than the register size + * will result in a crash or other undesired behavior. + * + * Returns the number of bytes written. On failure returns 0. + */ +QEMU_PLUGIN_API +int qemu_plugin_write_register(struct qemu_plugin_register *handle, + GByteArray *buf); + /** * qemu_plugin_read_memory_vaddr() - read from memory using a virtual addr= ess * @@ -915,22 +951,6 @@ QEMU_PLUGIN_API bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByteArray *data, size_t len); =20 -/** - * qemu_plugin_read_register() - read register for current vCPU - * - * @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 via the QEMU_PLUGIN_CB_R_REGS flag. - * - * Returns the size of the read register. The content of @buf is in target= byte - * order. On failure returns -1. - */ -QEMU_PLUGIN_API -int qemu_plugin_read_register(struct qemu_plugin_register *handle, - GByteArray *buf); - /** * qemu_plugin_scoreboard_new() - alloc a new scoreboard * diff --git a/plugins/api.c b/plugins/api.c index 3c9d4832e9..6514f2c76a 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -433,6 +433,25 @@ GArray *qemu_plugin_get_registers(void) return create_register_handles(regs); } =20 +int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray= *buf) +{ + g_assert(current_cpu); + + return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1); +} + +int qemu_plugin_write_register(struct qemu_plugin_register *reg, + GByteArray *buf) +{ + g_assert(current_cpu); + + if (buf->len =3D=3D 0 || qemu_plugin_get_cb_flags() !=3D QEMU_PLUGIN_C= B_RW_REGS) { + return -1; + } + + return gdb_write_register(current_cpu, buf->data, GPOINTER_TO_INT(reg)= - 1); +} + bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByteArray *data, size_t= len) { g_assert(current_cpu); @@ -453,13 +472,6 @@ bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByt= eArray *data, size_t len) return true; } =20 -int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray= *buf) -{ - g_assert(current_cpu); - - return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1); -} - struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_s= ize) { return plugin_scoreboard_new(element_size); --=20 2.49.0 From nobody Sun Feb 8 23:32:15 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1749498015; cv=none; d=zohomail.com; s=zohoarc; b=Y6M4MXxRxPsuh11mirdKGBFJde2KaFRCCnANGWmklx/4uRVbrQu8RDOz3D3UNiyIqzFRw6XmSkl/ZmuZoKAVkrenGKEH6UFAtETLO6TENz3/IK1oKRA7PYgrIwDtIXA1+LAuOKh17AkjR53O65cdQRDeTrhnBPFfRrefsi2+LrQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749498015; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=KFUOcBmGY84cd4f+W55MV8wVURuUm5Zqp4WwzjKvdts=; b=EFQ1I2g5gFg+z3NrlxvaPn7sU/PzIIpIeDgmwX5oG1R8RO9zM46Mq/4ZE4csv3DELytHs+JD5MhCT+Srv1eG1PzXz0BG5wwcC5y+nYJeIka+4AKtApD/vMLoncV7KjOYrQln6BNLdi+VWwrfk6DVsnih8mLEsUtfy0H0/JOdz5c= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749498015698317.6260957561128; Mon, 9 Jun 2025 12:40:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOiKc-0007Fh-0D; Mon, 09 Jun 2025 15:38:54 -0400 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 1uOiKX-0007DA-EH for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:49 -0400 Received: from mail-pg1-x535.google.com ([2607:f8b0:4864:20::535]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uOiKU-0004D6-TW for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:49 -0400 Received: by mail-pg1-x535.google.com with SMTP id 41be03b00d2f7-b26d7ddbfd7so5073419a12.0 for ; Mon, 09 Jun 2025 12:38:46 -0700 (PDT) Received: from shemhazi.lan ([50.46.174.34]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7482b083b03sm6095725b3a.83.2025.06.09.12.38.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 12:38:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749497925; x=1750102725; 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=KFUOcBmGY84cd4f+W55MV8wVURuUm5Zqp4WwzjKvdts=; b=YsgxG82bnWtF47+nhwpBO4bcytTxMgvqPZMny4M/bFO1yaFYCdfe1MvTFOv6CJ8igB E2hilKZUkJEPiugK0ouhVb4VGmVYOFia+E/wIib+0Fy+G6WkoMwqTDvH20OYncpPbmaZ oa/KC1EWGDyxcytNGTvs2YcUkIqfwLJPSWnQs4SFULwfEKcMe7JV/posV6BYpz+aqYUR 0JmFHFmRDu1dzgvcPxxG0XaimZtxf2WUTnyBy7MRffmKO9Xiizqh5CR/KikoXd2Pp5z+ ivE6Xcdk1kCHP9MVJgdXAap/UEI5yvYYf/Xg3NcsnuukjCKOKg0In4XYepBGBmdqF19s f3nw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749497925; x=1750102725; 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=KFUOcBmGY84cd4f+W55MV8wVURuUm5Zqp4WwzjKvdts=; b=dToEKG7tGIB37BXNx1P2Z3tWL1kYAwW42AhzMjHfaOsHNobK8NasNVlcac/iLirSNa 4XmsxN9MZFcoxux4mRqoS0wKctZCc7FZpNzC5BzprsqPBygXSbWoFBTQaMZL0fEcBHrK HFq+hg8QMI76mJzy1WbacY78a1sSoiGVl9WdzFLdejAqjMUU5X9rToeQ4/7m9UTnQ+c0 MOMTtq7sg0Jeci5I67VFJmMqx0NCOmB0yULMsn5i9QjJYCoGJUPCG3DlisOQ2FlORwZu /eYzu04GCuMVwCH4ikq23mJBXplnYbL2PvGpPcRDHw+vUQxiR7MrDJvcRQtFI/awZr9E GmZw== X-Gm-Message-State: AOJu0Yxzf+cZmFipKRNIbrIlt1Qq8s2IuFGzgtOZumPrIz05laVLUCm1 2jtUH1EUiP/GEoYLEUXtBiVWYUePPwJtUZiths7qQmW2MbBu38NKR/DyilimprQ/ X-Gm-Gg: ASbGncuXq2412Fvg4HyPRZ5bGJMmGEdKTTesAp62mcL3xy1QYvfZfLe9YR8Cxw0UQkX Sc4zN6TDD5vW/0qA7AQMSarJyeSo77w915Otc+uG4xCIKD/vBS8qe/HHlnJo8F3ChowgfXA8ruK Bqf1FiKI6Ihc7tM/Sf6Df+Vl25D2ONe6sCQxas4feMDlj/p6JrasYAOFFCgrsaMYfln3/Guwl8o ZGUv5e081N1rRgFyN+nBXkJKxMz/Fonfgh3AgsvqBY/+ULTIGiwCs7vI79EI0cvjV4hnCUvXNpE PZHE8XtG94mdqmwLe0jeMP0vQbOvtr5CVcPMgQvDYeFQSGjEwMZOVlTbUwIrEQ== X-Google-Smtp-Source: AGHT+IEX2Yu3IVE0ZHwMcIe6+quU7CQ2Kbf0MADgR2jFwAI5wIIl+kmivCkea4KjSc9Sux6MlikL0Q== X-Received: by 2002:a05:6a20:729f:b0:21a:efe4:5c6f with SMTP id adf61e73a8af0-21f78b16459mr44940637.2.1749497924680; Mon, 09 Jun 2025 12:38:44 -0700 (PDT) From: Rowan Hart To: qemu-devel@nongnu.org Cc: Zhao Liu , Eduardo Habkost , Pierrick Bouvier , Richard Henderson , Mahmoud Mandour , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Marcel Apfelbaum , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Yanan Wang , Alexandre Iooss , Rowan Hart Subject: [PATCH v11 3/8] plugins: Add enforcement of QEMU_PLUGIN_CB flags in register R/W callbacks Date: Mon, 9 Jun 2025 12:38:36 -0700 Message-ID: <20250609193841.348076-4-rowanbhart@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609193841.348076-1-rowanbhart@gmail.com> References: <20250609193841.348076-1-rowanbhart@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::535; envelope-from=rowanbhart@gmail.com; helo=mail-pg1-x535.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, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1749498018043116600 Content-Type: text/plain; charset="utf-8" This patch adds functionality to enforce the requested QEMU_PLUGIN_CB_ flags level passed when registering a callback function using the plugins API. Each time a callback is about to be invoked, a thread-local variable will be updated with the level that callback requested. Then, called API functions (in particular, the register read and write API) will call qemu_plugin_get_cb_flags() to check the level is at least the level they require. Signed-off-by: Rowan Hart Reviewed-by: Pierrick Bouvier --- accel/tcg/plugin-gen.c | 30 ++++++++++++++++++++++++++++++ include/hw/core/cpu.h | 1 + include/qemu/plugin.h | 15 +++++++++++++++ include/qemu/qemu-plugin.h | 19 +++++++++++++------ plugins/api.c | 4 ++++ plugins/core.c | 33 +++++++++++++++++++++++++++++++++ 6 files changed, 96 insertions(+), 6 deletions(-) diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index c1da753894..9920381a84 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -117,10 +117,20 @@ static TCGv_i32 gen_cpu_index(void) static void gen_udata_cb(struct qemu_plugin_regular_cb *cb) { TCGv_i32 cpu_index =3D gen_cpu_index(); + enum qemu_plugin_cb_flags cb_flags =3D + tcg_call_to_qemu_plugin_cb_flags(cb->info->flags); + TCGv_i32 flags =3D tcg_constant_i32(cb_flags); + TCGv_i32 clear_flags =3D tcg_constant_i32(QEMU_PLUGIN_CB_NO_REGS); + tcg_gen_st_i32(flags, tcg_env, + offsetof(CPUState, neg.plugin_cb_flags) - sizeof(CPUState)); tcg_gen_call2(cb->f.vcpu_udata, cb->info, NULL, tcgv_i32_temp(cpu_index), tcgv_ptr_temp(tcg_constant_ptr(cb->userp))); + tcg_gen_st_i32(clear_flags, tcg_env, + offsetof(CPUState, neg.plugin_cb_flags) - sizeof(CPUState)); tcg_temp_free_i32(cpu_index); + tcg_temp_free_i32(flags); + tcg_temp_free_i32(clear_flags); } =20 static TCGv_ptr gen_plugin_u64_ptr(qemu_plugin_u64 entry) @@ -173,10 +183,20 @@ static void gen_udata_cond_cb(struct qemu_plugin_cond= itional_cb *cb) tcg_gen_ld_i64(val, ptr, 0); tcg_gen_brcondi_i64(cond, val, cb->imm, after_cb); TCGv_i32 cpu_index =3D gen_cpu_index(); + enum qemu_plugin_cb_flags cb_flags =3D + tcg_call_to_qemu_plugin_cb_flags(cb->info->flags); + TCGv_i32 flags =3D tcg_constant_i32(cb_flags); + TCGv_i32 clear_flags =3D tcg_constant_i32(QEMU_PLUGIN_CB_NO_REGS); + tcg_gen_st_i32(flags, tcg_env, + offsetof(CPUState, neg.plugin_cb_flags) - sizeof(CPUState)); tcg_gen_call2(cb->f.vcpu_udata, cb->info, NULL, tcgv_i32_temp(cpu_index), tcgv_ptr_temp(tcg_constant_ptr(cb->userp))); + tcg_gen_st_i32(clear_flags, tcg_env, + offsetof(CPUState, neg.plugin_cb_flags) - sizeof(CPUState)); tcg_temp_free_i32(cpu_index); + tcg_temp_free_i32(flags); + tcg_temp_free_i32(clear_flags); gen_set_label(after_cb); =20 tcg_temp_free_i64(val); @@ -210,12 +230,22 @@ static void gen_mem_cb(struct qemu_plugin_regular_cb = *cb, qemu_plugin_meminfo_t meminfo, TCGv_i64 addr) { TCGv_i32 cpu_index =3D gen_cpu_index(); + enum qemu_plugin_cb_flags cb_flags =3D + tcg_call_to_qemu_plugin_cb_flags(cb->info->flags); + TCGv_i32 flags =3D tcg_constant_i32(cb_flags); + TCGv_i32 clear_flags =3D tcg_constant_i32(QEMU_PLUGIN_CB_NO_REGS); + tcg_gen_st_i32(flags, tcg_env, + offsetof(CPUState, neg.plugin_cb_flags) - sizeof(CPUState)); tcg_gen_call4(cb->f.vcpu_mem, cb->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_gen_st_i32(clear_flags, tcg_env, + offsetof(CPUState, neg.plugin_cb_flags) - sizeof(CPUState)); tcg_temp_free_i32(cpu_index); + tcg_temp_free_i32(flags); + tcg_temp_free_i32(clear_flags); } =20 static void inject_cb(struct qemu_plugin_dyn_cb *cb) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 1e87f7d393..d3cc9a5224 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -368,6 +368,7 @@ typedef struct CPUNegativeOffsetState { GArray *plugin_mem_cbs; uint64_t plugin_mem_value_low; uint64_t plugin_mem_value_high; + int32_t plugin_cb_flags; #endif IcountDecr icount_decr; bool can_do_io; diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index 9726a9ebf3..f355c7cb8a 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -209,6 +209,21 @@ void qemu_plugin_user_prefork_lock(void); */ void qemu_plugin_user_postfork(bool is_child); =20 +enum qemu_plugin_cb_flags tcg_call_to_qemu_plugin_cb_flags(int flags); + +static inline void qemu_plugin_set_cb_flags(CPUState *cpu, + enum qemu_plugin_cb_flags flag= s) +{ + assert(cpu); + cpu->neg.plugin_cb_flags =3D flags; +} + +static inline enum qemu_plugin_cb_flags qemu_plugin_get_cb_flags(void) +{ + assert(current_cpu); + return current_cpu->neg.plugin_cb_flags; +} + #else /* !CONFIG_PLUGIN */ =20 static inline void qemu_plugin_add_opts(void) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index cfe1692ecb..9c9ebf6ce0 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -254,9 +254,6 @@ typedef struct { * @QEMU_PLUGIN_CB_NO_REGS: callback does not access the CPU's regs * @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 QEMU_PLUGIN_CB_RW_REGS is unused, plugins cannot change - * system register state. */ enum qemu_plugin_cb_flags { QEMU_PLUGIN_CB_NO_REGS, @@ -901,7 +898,12 @@ GArray *qemu_plugin_get_registers(void); * @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 via the QEMU_PLUGIN_CB_R_REGS flag. + * explicitly requested via the QEMU_PLUGIN_CB_R_REGS flag, if called insi= de a + * callback that can be registered with a qemu_plugin_cb_flags argument. T= his + * function can also be used in any callback context that does not use a f= lags + * argument, such as in a callback registered with + * qemu_plugin_register_vcpu_init_cb(), except for callbacks registered wi= th + * qemu_plugin_register_atexit_cb() and qemu_plugin_register_flush_cb(). * * Returns the size of the read register. The content of @buf is in target= byte * order. On failure returns -1. @@ -916,8 +918,13 @@ int qemu_plugin_read_register(struct qemu_plugin_regis= ter *handle, * @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 write access= is - * explicitly requested via the QEMU_PLUGIN_CB_RW_REGS flag. + * This function is only available in a context that register read access = is + * explicitly requested via the QEMU_PLUGIN_CB_RW_REGS flag, if called ins= ide a + * callback that can be registered with a qemu_plugin_cb_flags argument. T= his + * function can also be used in any callback context that does not use a f= lags + * argument, such as in a callback registered with + * qemu_plugin_register_vcpu_init_cb(), except for callbacks registered wi= th + * qemu_plugin_register_atexit_cb() and qemu_plugin_register_flush_cb(). * * The size of @buf must be at least the size of the requested register. * Attempting to write a register with @buf smaller than the register size diff --git a/plugins/api.c b/plugins/api.c index 6514f2c76a..3f04399c26 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -437,6 +437,10 @@ int qemu_plugin_read_register(struct qemu_plugin_regis= ter *reg, GByteArray *buf) { g_assert(current_cpu); =20 + if (qemu_plugin_get_cb_flags() =3D=3D QEMU_PLUGIN_CB_NO_REGS) { + return -1; + } + return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1); } =20 diff --git a/plugins/core.c b/plugins/core.c index eb9281fe54..6ae5bbc0ef 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -15,6 +15,7 @@ #include "qemu/lockable.h" #include "qemu/option.h" #include "qemu/plugin.h" +#include "qemu/qemu-plugin.h" #include "qemu/queue.h" #include "qemu/rcu_queue.h" #include "qemu/rcu.h" @@ -266,7 +267,9 @@ static void qemu_plugin_vcpu_init__async(CPUState *cpu,= run_on_cpu_data unused) plugin_grow_scoreboards__locked(cpu); qemu_rec_mutex_unlock(&plugin.lock); =20 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_INIT); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } =20 void qemu_plugin_vcpu_init_hook(CPUState *cpu) @@ -279,7 +282,9 @@ void qemu_plugin_vcpu_exit_hook(CPUState *cpu) { bool success; =20 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_EXIT); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); =20 assert(cpu->cpu_index !=3D UNASSIGNED_CPU_INDEX); qemu_rec_mutex_lock(&plugin.lock); @@ -367,6 +372,7 @@ void plugin_register_dyn_cb__udata(GArray **arr, static TCGHelperInfo info[3] =3D { [QEMU_PLUGIN_CB_NO_REGS].flags =3D TCG_CALL_NO_RWG, [QEMU_PLUGIN_CB_R_REGS].flags =3D TCG_CALL_NO_WG, + [QEMU_PLUGIN_CB_RW_REGS].flags =3D 0, /* * Match qemu_plugin_vcpu_udata_cb_t: * void (*)(uint32_t, void *) @@ -396,6 +402,7 @@ void plugin_register_dyn_cond_cb__udata(GArray **arr, static TCGHelperInfo info[3] =3D { [QEMU_PLUGIN_CB_NO_REGS].flags =3D TCG_CALL_NO_RWG, [QEMU_PLUGIN_CB_R_REGS].flags =3D TCG_CALL_NO_WG, + [QEMU_PLUGIN_CB_RW_REGS].flags =3D 0, /* * Match qemu_plugin_vcpu_udata_cb_t: * void (*)(uint32_t, void *) @@ -434,6 +441,7 @@ void plugin_register_vcpu_mem_cb(GArray **arr, static TCGHelperInfo info[3] =3D { [QEMU_PLUGIN_CB_NO_REGS].flags =3D TCG_CALL_NO_RWG, [QEMU_PLUGIN_CB_R_REGS].flags =3D TCG_CALL_NO_WG, + [QEMU_PLUGIN_CB_RW_REGS].flags =3D 0, /* * Match qemu_plugin_vcpu_mem_cb_t: * void (*)(uint32_t, qemu_plugin_meminfo_t, uint64_t, void *) @@ -473,7 +481,9 @@ void qemu_plugin_tb_trans_cb(CPUState *cpu, struct qemu= _plugin_tb *tb) QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) { qemu_plugin_vcpu_tb_trans_cb_t func =3D cb->f.vcpu_tb_trans; =20 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); func(cb->ctx->id, tb); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } } =20 @@ -498,7 +508,9 @@ qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, ui= nt64_t a1, uint64_t a2, QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) { qemu_plugin_vcpu_syscall_cb_t func =3D cb->f.vcpu_syscall; =20 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); func(cb->ctx->id, cpu->cpu_index, num, a1, a2, a3, a4, a5, a6, a7,= a8); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } } =20 @@ -520,7 +532,9 @@ void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_= t num, int64_t ret) QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) { qemu_plugin_vcpu_syscall_ret_cb_t func =3D cb->f.vcpu_syscall_ret; =20 + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); func(cb->ctx->id, cpu->cpu_index, num, ret); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } } =20 @@ -528,14 +542,18 @@ void qemu_plugin_vcpu_idle_cb(CPUState *cpu) { /* idle and resume cb may be called before init, ignore in this case */ if (cpu->cpu_index < plugin.num_vcpus) { + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_IDLE); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } } =20 void qemu_plugin_vcpu_resume_cb(CPUState *cpu) { if (cpu->cpu_index < plugin.num_vcpus) { + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS); plugin_vcpu_cb__simple(cpu, QEMU_PLUGIN_EV_VCPU_RESUME); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } } =20 @@ -615,9 +633,13 @@ void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t v= addr, switch (cb->type) { case PLUGIN_CB_MEM_REGULAR: if (rw & cb->regular.rw) { + qemu_plugin_set_cb_flags(cpu, + tcg_call_to_qemu_plugin_cb_flags(cb->regular.info->fla= gs)); + cb->regular.f.vcpu_mem(cpu->cpu_index, make_plugin_meminfo(oi, rw), vaddr, cb->regular.userp); + qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS); } break; case PLUGIN_CB_INLINE_ADD_U64: @@ -760,3 +782,14 @@ void plugin_scoreboard_free(struct qemu_plugin_scorebo= ard *score) g_array_free(score->data, TRUE); g_free(score); } + +enum qemu_plugin_cb_flags tcg_call_to_qemu_plugin_cb_flags(int flags) +{ + if (flags & TCG_CALL_NO_RWG) { + return QEMU_PLUGIN_CB_NO_REGS; + } else if (flags & TCG_CALL_NO_WG) { + return QEMU_PLUGIN_CB_R_REGS; + } else { + return QEMU_PLUGIN_CB_RW_REGS; + } +} \ No newline at end of file --=20 2.49.0 From nobody Sun Feb 8 23:32:15 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1749497990; cv=none; d=zohomail.com; s=zohoarc; b=HB5FOaCUyzXV2TEjz87oETSpuxFPxmcKCpebZMCcfAOo11tPQNCR3fcXEPbqwU4Ih5ofwz9g7gBE99DaqAkS640oH8DL5dBUQ3nFmt3nNINb73ythjaMkV4Yuuk9NEVbVU7bgsI/eEWeAvqjD05xRF/od2maA3rtEsHqVP4ZCiE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749497990; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Xl2CsCbMIdd7IA6Ry113lx92Qe9OahNuvq02EUlL3YI=; b=O8Qt9wIbqvQM4NWQ55rPZwpKiYG21F4QV24XBaf+qjAl0g3AbaUkK/5XsVbDD0FPe6cbZGvBrPjNAz+hID5mxXyLGDUTeuTaZt0rhDvo5Xj61OybG5IsQhULE0Ms41yC1iJX8Ivhp6zXNX293G9qsnsfRK3S+v3N89TpNTNAm6Y= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749497990186460.47546928812983; Mon, 9 Jun 2025 12:39:50 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOiKb-0007Ew-3B; Mon, 09 Jun 2025 15:38:53 -0400 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 1uOiKX-0007DS-TE for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:49 -0400 Received: from mail-pf1-x431.google.com ([2607:f8b0:4864:20::431]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uOiKV-0004DB-7T for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:49 -0400 Received: by mail-pf1-x431.google.com with SMTP id d2e1a72fcca58-742af84818cso3300215b3a.1 for ; Mon, 09 Jun 2025 12:38:46 -0700 (PDT) Received: from shemhazi.lan ([50.46.174.34]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7482b083b03sm6095725b3a.83.2025.06.09.12.38.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 12:38:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749497925; x=1750102725; 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=Xl2CsCbMIdd7IA6Ry113lx92Qe9OahNuvq02EUlL3YI=; b=HcU+mCGC3Xb5AqRhS/tkdnEVEJ++q86FVe+7cMGCM/eUZMes8sS9y7GwWAHNgyoTUd TUAsdO0Ja40GYgMUkZYJLekrDW27XXqzM0XxjvJtBHpjFg45F0gopV9fLJ4Ukx5C/Ep3 HS8SCGQIlocfdnF5B6ePwGBljryggN6Mk87C2bzDuBK2cFengsiXWjoT2FnzDBnqGj7c 8VNALlRW2oxMCEeqT31YB9NP0zy4I8JqOcMThzLwtlP+QytTIA5wE06CBbuVY0Pm+23y p4UVuy24VwsKb2rHFaIUgypgGx8/AMIc1Wo8lruNFHzc3gVCftcoyrU8SnPmtSkpE1Ih 4sjA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749497925; x=1750102725; 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=Xl2CsCbMIdd7IA6Ry113lx92Qe9OahNuvq02EUlL3YI=; b=Ta+BSH8IlKhZOZcr4j6YkhukggEODrtWkqJkHxCDQ5WwbMhaapXhOhVgY7VEjwvd8t eucqZ28/oBabmWcb/ZhVNzOONCzVM9u9eUWPX60MiNLuhOcywc/ZJwyb4R3Wzym2Jg3n hKuR8x2i99DF3k6ydq+GOJtgYA6fiJgn7UG0H0H41zUoMr7OHkWnvkH8ljxERHBfxcS+ pM3Sy4Z0EzYkjsnsDyjTcJGGoVEmAEdrOVXDD4M3L2WGGlQ0kDh6p/zTpIHQoDHu9e+9 axzbJDo7wIuE8cGdYNC34mqiv9/QY0r9p6gzcsdp4SAUp5oZjlin0E6KCv8OWXd2Vfa6 kWig== X-Gm-Message-State: AOJu0Ywb+PQKqW5jibAnq+lgAtw++cYiffpxyhGXXYTPmzt1xAWra6XA oR2GUF5skh933ql4B8VVoG1njpCPm5dq6yvj6JZS1LJVr63urmi2H2/+9g/Fjkmz X-Gm-Gg: ASbGncvmIgntqxPjgPehFZMubIMveaJVQNVa/vVnzNJfmUGyDL+0/Ad/6hG9FbqqrQ2 bfZXOf4HZqKifjXYYnQiOtX8yPGCw+LOk9z9BEKaOViKAgEG2tKlDU5iugyBxg6+KVZO3NYmJSV Jfe2uYUPy5v2/ai8pyalAG7sZ+utQeFqswtUY9zMgRCQXcRQrjt1hRJPkWYuvmA8ECTO/bWtyL3 Ua4acBpJ2aShqcbr7upscmn0bwMkmpU7fewh1cOIG3WSGYttSaiPN8K/yp8weaxsD3oXq8RZEGD sLOZxagqqaBNMN9KU4eBd9RMaWixAdy2hB5LZbo7wrO/VpHeLF9CD04el9/UWg== X-Google-Smtp-Source: AGHT+IEjGKiL8UWIk+a8UiGmpId7If3TzYOhTD8OoAlhGmvBnnU5oF5JAw9A66/nphZWg0s7XNSt3Q== X-Received: by 2002:a05:6a00:1818:b0:746:285b:595c with SMTP id d2e1a72fcca58-74827e7f47amr20396160b3a.8.1749497925331; Mon, 09 Jun 2025 12:38:45 -0700 (PDT) From: Rowan Hart To: qemu-devel@nongnu.org Cc: Zhao Liu , Eduardo Habkost , Pierrick Bouvier , Richard Henderson , Mahmoud Mandour , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Marcel Apfelbaum , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Yanan Wang , Alexandre Iooss , novafacing Subject: [PATCH v11 4/8] plugins: Add memory virtual address write API Date: Mon, 9 Jun 2025 12:38:37 -0700 Message-ID: <20250609193841.348076-5-rowanbhart@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609193841.348076-1-rowanbhart@gmail.com> References: <20250609193841.348076-1-rowanbhart@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::431; envelope-from=rowanbhart@gmail.com; helo=mail-pf1-x431.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, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1749497991548116600 Content-Type: text/plain; charset="utf-8" From: novafacing This patch adds functions to the plugins API to allow reading and writing memory via virtual addresses. These functions only permit doing so on the current CPU, because there is no way to ensure consistency if plugins are allowed to read or write to other CPUs that aren't currently in the context of the plugin. Reviewed-by: Pierrick Bouvier Signed-off-by: Rowan Hart --- include/qemu/qemu-plugin.h | 21 +++++++++++++++++++++ plugins/api.c | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 9c9ebf6ce0..4167c46c2a 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -958,6 +958,27 @@ QEMU_PLUGIN_API bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByteArray *data, size_t len); =20 +/** + * qemu_plugin_write_memory_vaddr() - write to memory using a virtual addr= ess + * + * @addr: A virtual address to write to + * @data: A byte array containing the data to write + * + * The contents of @data will be written to memory starting at the virtual + * address @addr. + * + * This function does not guarantee consistency of writes, nor does it ens= ure + * that pending writes are flushed either before or after the write takes = place, + * so callers should take care to only call this function in vCPU context = (i.e. + * in callbacks) and avoid depending on the existence of data written usin= g this + * function which may be overwritten afterward. + * + * Returns true on success and false on failure. + */ +QEMU_PLUGIN_API +bool qemu_plugin_write_memory_vaddr(uint64_t addr, + GByteArray *data); + /** * qemu_plugin_scoreboard_new() - alloc a new scoreboard * diff --git a/plugins/api.c b/plugins/api.c index 3f04399c26..1f64a9ea64 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -476,6 +476,24 @@ bool qemu_plugin_read_memory_vaddr(uint64_t addr, GByt= eArray *data, size_t len) return true; } =20 +bool qemu_plugin_write_memory_vaddr(uint64_t addr, GByteArray *data) +{ + g_assert(current_cpu); + + if (data->len =3D=3D 0) { + return false; + } + + int result =3D cpu_memory_rw_debug(current_cpu, addr, data->data, + data->len, true); + + if (result < 0) { + return false; + } + + return true; +} + struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_s= ize) { return plugin_scoreboard_new(element_size); --=20 2.49.0 From nobody Sun Feb 8 23:32:15 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1749498054; cv=none; d=zohomail.com; s=zohoarc; b=l8QtZU4186VMKFhM6j+4mFIGeBCsMGYoiThjx+gaB3Y4dgyIEedNtPjlAI8w/4MUcKH6sHnpzMrtft4cUhLokzpReKWQ1Za8locD/c5BeU7gkwVVSEHZlgMY1i32+J3KxyWvkqDhRPvtjQv5/9k+lzb8szi4dKYNWlwqOuc419Y= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749498054; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=97wbn1fyVd354+uZeRkmCwxgLDzBnsPU4MLpqSMDiPM=; b=AWmeP62wcE4piLD5zXLxPiyRNin1kTIRtAie/Gg51NYGfpY2JWGyfsL6mc1xz3DODOQmp8swqDm0UePufngkYnWCCE1i6YGaT0HQs72N+dw9sShO0dKX1AKqAkqJ5X+8T0K9DOWv46NVcyJbh+v5hBiEYEr24mypMAjALu5SEMM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749498054965383.83529825058054; Mon, 9 Jun 2025 12:40:54 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOiKc-0007G6-IS; Mon, 09 Jun 2025 15:38:54 -0400 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 1uOiKY-0007Dc-8v for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:50 -0400 Received: from mail-pf1-x42f.google.com ([2607:f8b0:4864:20::42f]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uOiKV-0004DQ-QW for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:50 -0400 Received: by mail-pf1-x42f.google.com with SMTP id d2e1a72fcca58-7399a2dc13fso5240993b3a.2 for ; Mon, 09 Jun 2025 12:38:47 -0700 (PDT) Received: from shemhazi.lan ([50.46.174.34]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7482b083b03sm6095725b3a.83.2025.06.09.12.38.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 12:38:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749497926; x=1750102726; 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=97wbn1fyVd354+uZeRkmCwxgLDzBnsPU4MLpqSMDiPM=; b=K0MCmgdJoEbT2QQEKk3dvzDZWOJI2SZdSAYEF/N3bYD2/gK65TTUjM1OarQSAXYMAz jxHNw5ucBNkzi74G75l1k9OXj0L0Eg4OCvM0Aztye8XmW23Q+VdOdWHYVem0NC04InZ4 L8/qOiqIGCYtvWLjSxqdhfPvUhbVrtAv6aLuWQcv0a4S+f9BYEcU7vO2z1PN5gatDyw8 2bW3iOXEotmenC9tYZ+5Pg1yn0HlJ8unXiUoXShluQd31MBg5yScaAwQih5gAAdI8ZMk 1mhRaLqdwv/wUscrGAoo7TroVlFmqejtqZwHvtT4HSDqYY14LI2s8uOKMxfE8N6h5DHa Td6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749497926; x=1750102726; 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=97wbn1fyVd354+uZeRkmCwxgLDzBnsPU4MLpqSMDiPM=; b=eCrP9QrsxPcv1CvM1n2kH0wcp7iWBX93FatKY4RsUaMWiCClFwPiSRQLj5XLpJfjel V2NKNzptCX8EkACRA84f4DtzpFgIGS6WWICgImc59Bb3EefVWxLWSM3nWiBbZF/QUZxE phjX0XuI/3rgsiWw6nyRj29vSRCKmtwu3AWvFiGsG2GEURa+u/UvZaktRhihTFzW/Lmj Tx4UBG2YlQBGszkXVgbkpLBQKRzxKL20IYbeEa5inGVGu82w9mFLMp3TlFhG6YMNOBnZ GV1FVDdsZbLMzEMMBVO7iu9zeT3Te8ojuJlqUcH9Q8BiW+6TmSbMbIiNReJP4UomGSGx 8G0w== X-Gm-Message-State: AOJu0YyAyskAayqkGLTTi9/I6Pb3M7Xkh75H0DGM4s3ORElCV4I9PjlX APJi7Otk3hVgaAVRgIeJx+Yc87lEzdgq1MevWLOmeOoW1CmZPl8U8oEuIcRP7zK1 X-Gm-Gg: ASbGncszxZJt68d2uysabzILsEhhF5DHvcmPExcE34cDcwcpAkdvvotV4JYWfE+8B/0 QNrqInxVoW0Bxzb0hJzGETsBHpO/6YTDAe3prkuzoDAalEYnjjPoZAYCLcSMRZd/NoW2gWCHRuh QfSos/qQyYiBxWVMJX+x+c+mZF7qyo5KZJBGjfdHIrn+be9JUjZDDLEpXEJxId+gfhdjOFZZJwy mR+zsXER0tHuJGMbD80Pa/lJKmJDWGBEP6oc6UIWSR/e7m8WuQCwPenbtsqTosNSMcTnnrfwkEZ WBf4lGZC+BWq3c2o2gbdndMOVIG855MIhAWr2taRkI7Sk1rit/4= X-Google-Smtp-Source: AGHT+IGgLZh+NZt3ECBtLe+F/cuQOi8hQUd2sRRPrbG1U2E63dLXEeY40yu9fpafVmnG8kH4XztXDQ== X-Received: by 2002:a05:6a00:1885:b0:746:3200:620 with SMTP id d2e1a72fcca58-74827e82607mr16769141b3a.9.1749497926170; Mon, 09 Jun 2025 12:38:46 -0700 (PDT) From: Rowan Hart To: qemu-devel@nongnu.org Cc: Zhao Liu , Eduardo Habkost , Pierrick Bouvier , Richard Henderson , Mahmoud Mandour , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Marcel Apfelbaum , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Yanan Wang , Alexandre Iooss , novafacing Subject: [PATCH v11 5/8] plugins: Add memory hardware address read/write API Date: Mon, 9 Jun 2025 12:38:38 -0700 Message-ID: <20250609193841.348076-6-rowanbhart@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609193841.348076-1-rowanbhart@gmail.com> References: <20250609193841.348076-1-rowanbhart@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::42f; envelope-from=rowanbhart@gmail.com; helo=mail-pf1-x42f.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, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1749498056655116600 Content-Type: text/plain; charset="utf-8" From: novafacing This patch adds functions to the plugins API to allow plugins to read and write memory via hardware addresses. The functions use the current address space of the current CPU in order to avoid exposing address space information to users. A later patch may want to add a function to permit a specified address space, for example to facilitate architecture-specific plugins that want to operate on them, for example reading ARM secure memory. Reviewed-by: Pierrick Bouvier Signed-off-by: Rowan Hart --- include/qemu/qemu-plugin.h | 93 ++++++++++++++++++++++++++++++++++++ plugins/api.c | 97 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 4167c46c2a..5eecdccc67 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -979,6 +979,99 @@ QEMU_PLUGIN_API bool qemu_plugin_write_memory_vaddr(uint64_t addr, GByteArray *data); =20 +/** + * enum qemu_plugin_hwaddr_operation_result - result of a memory operation + * + * @QEMU_PLUGIN_HWADDR_OPERATION_OK: hwaddr operation succeeded + * @QEMU_PLUGIN_HWADDR_OPERATION_ERROR: unexpected error occurred + * @QEMU_PLUGIN_HWADDR_OPERATION_DEVICE_ERROR: error in memory device + * @QEMU_PLUGIN_HWADDR_OPERATION_ACCESS_DENIED: permission error + * @QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS: address was invalid + * @QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS_SPACE: invalid address sp= ace + */ +enum qemu_plugin_hwaddr_operation_result { + QEMU_PLUGIN_HWADDR_OPERATION_OK, + QEMU_PLUGIN_HWADDR_OPERATION_ERROR, + QEMU_PLUGIN_HWADDR_OPERATION_DEVICE_ERROR, + QEMU_PLUGIN_HWADDR_OPERATION_ACCESS_DENIED, + QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS, + QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS_SPACE, +}; + +/** + * qemu_plugin_read_memory_hwaddr() - read from memory using a hardware ad= dress + * + * @addr: The physical address to read from + * @data: A byte array to store data into + * @len: The number of bytes to read, starting from @addr + * + * @len bytes of data is read from the current memory space for the current + * vCPU starting at @addr and stored into @data. If @data is not large eno= ugh to + * hold @len bytes, it will be expanded to the necessary size, reallocatin= g if + * necessary. @len must be greater than 0. + * + * This function does not ensure writes are flushed prior to reading, so + * callers should take care when calling this function in plugin callbacks= to + * avoid attempting to read data which may not yet be written and should u= se + * the memory callback API instead. + * + * This function is only valid for softmmu targets. + * + * Returns a qemu_plugin_hwaddr_operation_result indicating the result of = the + * operation. + */ +QEMU_PLUGIN_API +enum qemu_plugin_hwaddr_operation_result +qemu_plugin_read_memory_hwaddr(uint64_t addr, GByteArray *data, size_t len= ); + +/** + * qemu_plugin_write_memory_hwaddr() - write to memory using a hardware ad= dress + * + * @addr: A physical address to write to + * @data: A byte array containing the data to write + * + * The contents of @data will be written to memory starting at the hardware + * address @addr in the current address space for the current vCPU. + * + * This function does not guarantee consistency of writes, nor does it ens= ure + * that pending writes are flushed either before or after the write takes = place, + * so callers should take care when calling this function in plugin callba= cks to + * avoid depending on the existence of data written using this function wh= ich + * may be overwritten afterward. In addition, this function requires that = the + * pages containing the address are not locked. Practically, this means th= at you + * should not write instruction memory in a current translation block insi= de a + * callback registered with qemu_plugin_register_vcpu_tb_trans_cb. + * + * You can, for example, write instruction memory in a current translation= block + * in a callback registered with qemu_plugin_register_vcpu_tb_exec_cb, alt= hough + * be aware that the write will not be flushed until after the translation= block + * has finished executing. In general, this function should be used to wr= ite + * data memory or to patch code at a known address, not in a current trans= lation + * block. + * + * This function is only valid for softmmu targets. + * + * Returns a qemu_plugin_hwaddr_operation_result indicating the result of = the + * operation. + */ +QEMU_PLUGIN_API +enum qemu_plugin_hwaddr_operation_result +qemu_plugin_write_memory_hwaddr(uint64_t addr, GByteArray *data); + +/** + * qemu_plugin_translate_vaddr() - translate virtual address for current v= CPU + * + * @vaddr: virtual address to translate + * @hwaddr: pointer to store the physical address + * + * This function is only valid in vCPU context (i.e. in callbacks) and is = only + * valid for softmmu targets. + * + * Returns true on success and false on failure. + */ +QEMU_PLUGIN_API +bool qemu_plugin_translate_vaddr(uint64_t vaddr, uint64_t *hwaddr); + /** * qemu_plugin_scoreboard_new() - alloc a new scoreboard * diff --git a/plugins/api.c b/plugins/api.c index 1f64a9ea64..eac04cc1f6 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -39,6 +39,7 @@ #include "qemu/main-loop.h" #include "qemu/plugin.h" #include "qemu/log.h" +#include "system/memory.h" #include "tcg/tcg.h" #include "exec/gdbstub.h" #include "exec/target_page.h" @@ -494,6 +495,102 @@ bool qemu_plugin_write_memory_vaddr(uint64_t addr, GB= yteArray *data) return true; } =20 +enum qemu_plugin_hwaddr_operation_result +qemu_plugin_read_memory_hwaddr(hwaddr addr, GByteArray *data, size_t len) +{ +#ifdef CONFIG_SOFTMMU + if (len =3D=3D 0) { + return QEMU_PLUGIN_HWADDR_OPERATION_ERROR; + } + + g_assert(current_cpu); + + + int as_idx =3D cpu_asidx_from_attrs(current_cpu, MEMTXATTRS_UNSPECIFIE= D); + AddressSpace *as =3D cpu_get_address_space(current_cpu, as_idx); + + if (as =3D=3D NULL) { + return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS_SPACE; + } + + g_byte_array_set_size(data, len); + MemTxResult res =3D address_space_rw(as, addr, + MEMTXATTRS_UNSPECIFIED, data->data, + data->len, false); + + switch (res) { + case MEMTX_OK: + return QEMU_PLUGIN_HWADDR_OPERATION_OK; + case MEMTX_ERROR: + return QEMU_PLUGIN_HWADDR_OPERATION_DEVICE_ERROR; + case MEMTX_DECODE_ERROR: + return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS; + case MEMTX_ACCESS_ERROR: + return QEMU_PLUGIN_HWADDR_OPERATION_ACCESS_DENIED; + default: + return QEMU_PLUGIN_HWADDR_OPERATION_ERROR; + } +#else + return QEMU_PLUGIN_HWADDR_OPERATION_ERROR; +#endif +} + +enum qemu_plugin_hwaddr_operation_result +qemu_plugin_write_memory_hwaddr(hwaddr addr, GByteArray *data) +{ +#ifdef CONFIG_SOFTMMU + if (data->len =3D=3D 0) { + return QEMU_PLUGIN_HWADDR_OPERATION_ERROR; + } + + g_assert(current_cpu); + + int as_idx =3D cpu_asidx_from_attrs(current_cpu, MEMTXATTRS_UNSPECIFIE= D); + AddressSpace *as =3D cpu_get_address_space(current_cpu, as_idx); + + if (as =3D=3D NULL) { + return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS_SPACE; + } + + MemTxResult res =3D address_space_rw(as, addr, + MEMTXATTRS_UNSPECIFIED, data->data, + data->len, true); + switch (res) { + case MEMTX_OK: + return QEMU_PLUGIN_HWADDR_OPERATION_OK; + case MEMTX_ERROR: + return QEMU_PLUGIN_HWADDR_OPERATION_DEVICE_ERROR; + case MEMTX_DECODE_ERROR: + return QEMU_PLUGIN_HWADDR_OPERATION_INVALID_ADDRESS; + case MEMTX_ACCESS_ERROR: + return QEMU_PLUGIN_HWADDR_OPERATION_ACCESS_DENIED; + default: + return QEMU_PLUGIN_HWADDR_OPERATION_ERROR; + } +#else + return QEMU_PLUGIN_HWADDR_OPERATION_ERROR; +#endif +} + +bool qemu_plugin_translate_vaddr(uint64_t vaddr, uint64_t *hwaddr) +{ +#ifdef CONFIG_SOFTMMU + g_assert(current_cpu); + + uint64_t res =3D cpu_get_phys_page_debug(current_cpu, vaddr); + + if (res =3D=3D (uint64_t)-1) { + return false; + } + + *hwaddr =3D res | (vaddr & ~TARGET_PAGE_MASK); + + return true; +#else + return false; +#endif +} + struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_s= ize) { return plugin_scoreboard_new(element_size); --=20 2.49.0 From nobody Sun Feb 8 23:32:15 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1749498045; cv=none; d=zohomail.com; s=zohoarc; b=fqvNwnO849yYmRby3S5jtwZ6FY9Le4bHjpQBuOWscAU1c4H+AyDzIenwTEOA6Xc2RYj2V+rfiDZV1naa4cYvOLcDttghYXZR5OD53ylozwzWnRnlo5uh1hw7rvOB0Q/a0jrpKvI7XtF4XiQPfl4XwajPvA2RnQx2Xi2Khul8IrE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749498045; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=2ap6I1EkC90RWD1sn5nrnpOFuEPRFLgHmwY9jqJf898=; b=gbTaL5qCL3th1QBxKsnnXBRliLIBdKHEr34b7QUvI8yi+ChC9R3Nn+2oENF3g11pGIq4mELEDNZGRkl9i0/XuInsAKlT4XUD/igKOOYKhNGZ5o8Fufo9ZKibYc0Q9aoE7xMUTnGZf46uFImk/L15X+E4n70ew12j669JPKlr6a4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749498045631896.2471440135472; Mon, 9 Jun 2025 12:40:45 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOiKd-0007GG-AO; Mon, 09 Jun 2025 15:38:55 -0400 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 1uOiKZ-0007ED-RJ for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:52 -0400 Received: from mail-pf1-x433.google.com ([2607:f8b0:4864:20::433]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uOiKX-0004DZ-7V for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:51 -0400 Received: by mail-pf1-x433.google.com with SMTP id d2e1a72fcca58-742c46611b6so5899930b3a.1 for ; Mon, 09 Jun 2025 12:38:48 -0700 (PDT) Received: from shemhazi.lan ([50.46.174.34]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7482b083b03sm6095725b3a.83.2025.06.09.12.38.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 12:38:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749497927; x=1750102727; 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=2ap6I1EkC90RWD1sn5nrnpOFuEPRFLgHmwY9jqJf898=; b=d4O0HsAY3YOpoK9w/FhMfg/2t4HzGcRL+OkNEIyQOK+Sq1jCVvtXCEMMCx3l40Tpmy KGCvv/fIDSTUn1a+LtTLjSvQyxMVP6iisNWvl91lt3kalvVhVGXCrpAR7b7reTer5Igt I9PZr+2zEdLHSOQXvJf2pvdhCHfwwxk2WxYiX1shqM63HaG8MsXuluQPgZPF51qLjZps J0+9ZxSBAjTh+CmMrXzp5w4cyod2S23hyUjW6sCgfxaOvGKyiNYGi+PQEBnNl63oNI4B 0MOeQ4CS9Rf3DEjV9F4DljvbfTVvEcfpFWje53iUYEFFUi/ZZ/1aFGoiXXx/EyhAoKE4 jllQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749497927; x=1750102727; 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=2ap6I1EkC90RWD1sn5nrnpOFuEPRFLgHmwY9jqJf898=; b=QE3RXD4oYyPXpLf64Pazu3n2UJT+Gp1vP+mSI5/4vfFgawnWAlro86HILs9YRIvic/ yv6qMOHAkbk8x1GCu8aSYUlJffJgMZ7Z0v9Z+BJ9+L5T9ZW4jGAS/rb4553kO1q3f2t8 5YLscXDSsLrZPhdGf4Ox7w1QsVWIrgJQF2r7rniq8YtdPa1/EOrMm2ITrHXuGIwSxL9Q tPeGo1jDUChfyG0SzJmNOpWNMiABl1vBtXeR3NTMZSBQ0v7YM2m1wYojNs/qYf3SCCNL 2Y2MwTPrxg+0poBrtWfZjyV/OGv1zzwgn7UaKamHBfKRWeYnFwJhOYDyoR0Rmjfw4L+3 pAEw== X-Gm-Message-State: AOJu0YxX4aIjamWApTLZaGDsi2+QkyMgccupHljitylmP0Ocvzpbvl8g DZLBTs3b+UR/RO2kRCRa3GBg61PWe3E6sNrwaze6B0MFGCl2Va6RxUWWKffm4tvW X-Gm-Gg: ASbGncth/XubruuVuTB4MMlk6P7UvPVDsC55aou5XMF77jPTOXJDisR9188hIyXxVr6 mNbH26tNe8Uiuv5dtOQECZZy0ge10ktME6OcoFY3p+o6wBON/eJ3RYcfmqB7GEk3M15E6P3IMjl +sPhOsUtXWp1oEsSnD9LCsLusiRFpi4hJEgamGN3K6vtJQC6veZjOBcRwPmi+rOJrscWyRXeusy fX+F6q1/2RRTejCvjB3mmlws1aeQCVzHomNSoOn8nqkrReI9oIxuvAqGp7ieibE8zs6O8cVTlTO 9OSAwi3EqOSDddF0D9M9ASC0RRD5eUlq6Q6FJkGu/29Apsh0BtE= X-Google-Smtp-Source: AGHT+IHMuoKDGs2YjyhzQl7pCPF/OwtP4QVj5xuZVKeIXIpAymUXg3yIRS4xfu+E1t6ibiEFrVhwMg== X-Received: by 2002:a05:6a00:929c:b0:736:53f2:87bc with SMTP id d2e1a72fcca58-74827ea64c2mr19647710b3a.13.1749497926993; Mon, 09 Jun 2025 12:38:46 -0700 (PDT) From: Rowan Hart To: qemu-devel@nongnu.org Cc: Zhao Liu , Eduardo Habkost , Pierrick Bouvier , Richard Henderson , Mahmoud Mandour , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Marcel Apfelbaum , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Yanan Wang , Alexandre Iooss , novafacing Subject: [PATCH v11 6/8] plugins: Add patcher plugin and test Date: Mon, 9 Jun 2025 12:38:39 -0700 Message-ID: <20250609193841.348076-7-rowanbhart@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609193841.348076-1-rowanbhart@gmail.com> References: <20250609193841.348076-1-rowanbhart@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::433; envelope-from=rowanbhart@gmail.com; helo=mail-pf1-x433.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, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1749498046404116600 Content-Type: text/plain; charset="utf-8" From: novafacing This patch adds a plugin that exercises the virtual and hardware memory read-write API functions added in a previous patch. The plugin takes a target and patch byte sequence, and will overwrite any instruction matching the target byte sequence with the patch. Signed-off-by: Rowan Hart --- tests/tcg/Makefile.target | 1 + tests/tcg/plugins/meson.build | 2 +- tests/tcg/plugins/patch.c | 297 ++++++++++++++++++++++ tests/tcg/x86_64/Makefile.softmmu-target | 32 ++- tests/tcg/x86_64/system/patch-target.c | 27 ++ tests/tcg/x86_64/system/validate-patch.py | 39 +++ 6 files changed, 392 insertions(+), 6 deletions(-) create mode 100644 tests/tcg/plugins/patch.c create mode 100644 tests/tcg/x86_64/system/patch-target.c create mode 100755 tests/tcg/x86_64/system/validate-patch.py diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index 95ff76ea44..4b709a9d18 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -176,6 +176,7 @@ RUN_TESTS+=3D$(EXTRA_RUNS) # Some plugins need additional arguments above the default to fully # exercise things. We can define them on a per-test basis here. run-plugin-%-with-libmem.so: PLUGIN_ARGS=3D$(COMMA)inline=3Dtrue +run-plugin-%-with-libpatch.so: PLUGIN_ARGS=3D$(COMMA)target=3Dffffffff$(CO= MMA)patch=3D00000000 =20 ifeq ($(filter %-softmmu, $(TARGET)),) run-%: % diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build index 41f02f2c7f..163042e601 100644 --- a/tests/tcg/plugins/meson.build +++ b/tests/tcg/plugins/meson.build @@ -1,6 +1,6 @@ t =3D [] if get_option('plugins') - foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall'] + foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall',= 'patch'] if host_os =3D=3D 'windows' t +=3D shared_module(i, files(i + '.c') + '../../../contrib/plugins/= win32_linker.c', include_directories: '../../../include/qemu', diff --git a/tests/tcg/plugins/patch.c b/tests/tcg/plugins/patch.c new file mode 100644 index 0000000000..6e83418b85 --- /dev/null +++ b/tests/tcg/plugins/patch.c @@ -0,0 +1,297 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This plugin patches instructions matching a pattern to a different + * instruction as they execute + * + */ + +#include "glib.h" +#include "glibconfig.h" + +#include +#include +#include + +QEMU_PLUGIN_EXPORT int qemu_plugin_version =3D QEMU_PLUGIN_VERSION; + +static bool use_hwaddr; +static bool debug_insns; +static GByteArray *target_data; +static GByteArray *patch_data; + +/** + * Parse a string of hexadecimal digits into a GByteArray. The string must= be + * even length + */ +static GByteArray *str_to_bytes(const char *str) +{ + GByteArray *bytes =3D g_byte_array_new(); + char byte[3] =3D {0}; + size_t len =3D strlen(str); + guint8 value =3D 0; + + if (len % 2 !=3D 0) { + g_byte_array_free(bytes, true); + return NULL; + } + + for (size_t i =3D 0; i < len; i +=3D 2) { + byte[0] =3D str[i]; + byte[1] =3D str[i + 1]; + value =3D (guint8)g_ascii_strtoull(byte, NULL, 16); + g_byte_array_append(bytes, &value, 1); + } + + return bytes; +} + +static void patch_hwaddr(unsigned int vcpu_index, void *userdata) +{ + uint64_t addr =3D (uint64_t)userdata; + GString *str =3D g_string_new(NULL); + g_string_printf(str, "patching: @0x%" + PRIx64 "\n", + addr); + qemu_plugin_outs(str->str); + g_string_free(str, true); + + enum qemu_plugin_hwaddr_operation_result result =3D + qemu_plugin_write_memory_hwaddr(addr, patch_data); + + + if (result !=3D QEMU_PLUGIN_HWADDR_OPERATION_OK) { + GString *errmsg =3D g_string_new(NULL); + g_string_printf(errmsg, "Failed to write memory: %d\n", result); + qemu_plugin_outs(errmsg->str); + g_string_free(errmsg, true); + return; + } + + GByteArray *read_data =3D g_byte_array_new(); + + result =3D qemu_plugin_read_memory_hwaddr(addr, read_data, + patch_data->len); + + qemu_plugin_outs("Reading memory...\n"); + + if (result !=3D QEMU_PLUGIN_HWADDR_OPERATION_OK) { + GString *errmsg =3D g_string_new(NULL); + g_string_printf(errmsg, "Failed to read memory: %d\n", result); + qemu_plugin_outs(errmsg->str); + g_string_free(errmsg, true); + return; + } + + if (memcmp(patch_data->data, read_data->data, patch_data->len) !=3D 0)= { + qemu_plugin_outs("Failed to read back written data\n"); + } + + qemu_plugin_outs("Success!\n"); + + return; +} + +static void patch_vaddr(unsigned int vcpu_index, void *userdata) +{ + uint64_t addr =3D (uint64_t)userdata; + uint64_t hwaddr =3D 0; + if (!qemu_plugin_translate_vaddr(addr, &hwaddr)) { + qemu_plugin_outs("Failed to translate vaddr\n"); + return; + } + GString *str =3D g_string_new(NULL); + g_string_printf(str, "patching: @0x%" + PRIx64 " hw: @0x%" PRIx64 "\n", + addr, hwaddr); + qemu_plugin_outs(str->str); + g_string_free(str, true); + + qemu_plugin_outs("Writing memory (vaddr)...\n"); + + if (!qemu_plugin_write_memory_vaddr(addr, patch_data)) { + qemu_plugin_outs("Failed to write memory\n"); + return; + } + + qemu_plugin_outs("Reading memory (vaddr)...\n"); + + + GByteArray *read_data =3D g_byte_array_new(); + + if (!qemu_plugin_read_memory_vaddr(addr, read_data, patch_data->len)) { + qemu_plugin_outs("Failed to read memory\n"); + return; + } + + if (memcmp(patch_data->data, read_data->data, patch_data->len) !=3D 0)= { + qemu_plugin_outs("Failed to read back written data\n"); + } + + qemu_plugin_outs("Success!\n"); + + return; +} + +static void debug_disas(unsigned int vcpu_index, void *userdata) +{ + GString *debug_info =3D (GString *)userdata; + qemu_plugin_outs(debug_info->str); +} + +static void debug_print_newline(unsigned int vcpu_index, void *userdata) +{ + qemu_plugin_outs("\n"); +} + +/* + * Callback on translation of a translation block. + */ +static void vcpu_tb_trans_cb(qemu_plugin_id_t id, struct qemu_plugin_tb *t= b) +{ + uint64_t addr =3D 0; + GByteArray *insn_data =3D g_byte_array_new(); + for (size_t i =3D 0; i < qemu_plugin_tb_n_insns(tb); i++) { + struct qemu_plugin_insn *insn =3D qemu_plugin_tb_get_insn(tb, i); + + if (use_hwaddr) { + uint64_t vaddr =3D qemu_plugin_insn_vaddr(insn); + if (!qemu_plugin_translate_vaddr(vaddr, &addr)) { + qemu_plugin_outs("Failed to translate vaddr\n"); + continue; + } + } else { + addr =3D qemu_plugin_insn_vaddr(insn); + } + + g_byte_array_set_size(insn_data, qemu_plugin_insn_size(insn)); + qemu_plugin_insn_data(insn, insn_data->data, insn_data->len); + + if (insn_data->len >=3D target_data->len && + !memcmp(insn_data->data, target_data->data, + MIN(target_data->len, insn_data->len))) { + if (use_hwaddr) { + qemu_plugin_register_vcpu_tb_exec_cb(tb, patch_hwaddr, + QEMU_PLUGIN_CB_NO_REG= S, + (void *)addr); + } else { + qemu_plugin_register_vcpu_tb_exec_cb(tb, patch_vaddr, + QEMU_PLUGIN_CB_NO_REG= S, + (void *)addr); + } + } + } + for (size_t i =3D 0; i < qemu_plugin_tb_n_insns(tb); i++) { + struct qemu_plugin_insn *insn =3D qemu_plugin_tb_get_insn(tb, i); + uint64_t vaddr =3D qemu_plugin_insn_vaddr(insn); + uint64_t hwaddr =3D (uint64_t)qemu_plugin_insn_haddr(insn); + uint64_t translated_hwaddr =3D 0; + if (!qemu_plugin_translate_vaddr(vaddr, &translated_hwaddr)) { + qemu_plugin_outs("Failed to translate vaddr\n"); + continue; + } + char *disas =3D qemu_plugin_insn_disas(insn); + GString *str =3D g_string_new(NULL); + g_string_printf(str, + "vaddr: 0x%" PRIx64 " hwaddr: 0x%" PRIx64 + " translated: 0x%" PRIx64 " : %s\n", + vaddr, hwaddr, translated_hwaddr, disas); + g_free(disas); + if (debug_insns) { + qemu_plugin_register_vcpu_insn_exec_cb(insn, debug_disas, + QEMU_PLUGIN_CB_NO_REGS, + str); + } + + } + + if (debug_insns) { + qemu_plugin_register_vcpu_tb_exec_cb(tb, debug_print_newline, + QEMU_PLUGIN_CB_NO_REGS, + NULL); + } + + g_byte_array_free(insn_data, true); +} + +static void usage(void) +{ + fprintf(stderr, "Usage: ,target=3D,patch=3D" + "[,use_hwaddr=3D]" + "[,debug_insns=3D]\n"); +} + +/* + * Called when the plugin is installed + */ +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, + const qemu_info_t *info, int ar= gc, + char **argv) +{ + + use_hwaddr =3D true; + debug_insns =3D false; + target_data =3D NULL; + patch_data =3D NULL; + + if (argc > 4) { + usage(); + return -1; + } + + for (size_t i =3D 0; i < argc; i++) { + char *opt =3D argv[i]; + g_auto(GStrv) tokens =3D g_strsplit(opt, "=3D", 2); + if (g_strcmp0(tokens[0], "use_hwaddr") =3D=3D 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &use_hwaddr)= ) { + fprintf(stderr, + "Failed to parse boolean argument use_hwaddr\n"); + return -1; + } + } else if (g_strcmp0(tokens[0], "debug_insns") =3D=3D 0) { + if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &debug_insns= )) { + fprintf(stderr, + "Failed to parse boolean argument debug_insns\n"); + return -1; + } + } else if (g_strcmp0(tokens[0], "target") =3D=3D 0) { + target_data =3D str_to_bytes(tokens[1]); + if (!target_data) { + fprintf(stderr, + "Failed to parse target bytes.\n"); + return -1; + } + } else if (g_strcmp0(tokens[0], "patch") =3D=3D 0) { + patch_data =3D str_to_bytes(tokens[1]); + if (!patch_data) { + fprintf(stderr, "Failed to parse patch bytes.\n"); + return -1; + } + } else { + fprintf(stderr, "Unknown argument: %s\n", tokens[0]); + usage(); + return -1; + } + } + + if (!target_data) { + fprintf(stderr, "target argument is required\n"); + usage(); + return -1; + } + + if (!patch_data) { + fprintf(stderr, "patch argument is required\n"); + usage(); + return -1; + } + + if (target_data->len !=3D patch_data->len) { + fprintf(stderr, "Target and patch data must be the same length\n"); + return -1; + } + + qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans_cb); + + return 0; +} diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Ma= kefile.softmmu-target index ef6bcb4dc7..8d3a067c33 100644 --- a/tests/tcg/x86_64/Makefile.softmmu-target +++ b/tests/tcg/x86_64/Makefile.softmmu-target @@ -7,18 +7,27 @@ # =20 I386_SYSTEM_SRC=3D$(SRC_PATH)/tests/tcg/i386/system -X64_SYSTEM_SRC=3D$(SRC_PATH)/tests/tcg/x86_64/system +X86_64_SYSTEM_SRC=3D$(SRC_PATH)/tests/tcg/x86_64/system =20 # These objects provide the basic boot code and helper functions for all t= ests CRT_OBJS=3Dboot.o =20 -CRT_PATH=3D$(X64_SYSTEM_SRC) -LINK_SCRIPT=3D$(X64_SYSTEM_SRC)/kernel.ld +X86_64_TEST_C_SRCS=3D$(wildcard $(X86_64_SYSTEM_SRC)/*.c) +X86_64_TEST_S_SRCS=3D + +X86_64_C_TESTS =3D $(patsubst $(X86_64_SYSTEM_SRC)/%.c, %, $(X86_64_TEST_C= _SRCS)) +X86_64_S_TESTS =3D $(patsubst $(X86_64_SYSTEM_SRC)/%.S, %, $(X86_64_TEST_S= _SRCS)) + +X86_64_TESTS =3D $(X86_64_C_TESTS) +X86_64_TESTS +=3D $(X86_64_S_TESTS) + +CRT_PATH=3D$(X86_64_SYSTEM_SRC) +LINK_SCRIPT=3D$(X86_64_SYSTEM_SRC)/kernel.ld LDFLAGS=3D-Wl,-T$(LINK_SCRIPT) -Wl,-melf_x86_64 CFLAGS+=3D-nostdlib -ggdb -O0 $(MINILIB_INC) LDFLAGS+=3D-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc =20 -TESTS+=3D$(MULTIARCH_TESTS) +TESTS+=3D$(X86_64_TESTS) $(MULTIARCH_TESTS) EXTRA_RUNS+=3D$(MULTIARCH_RUNS) =20 # building head blobs @@ -27,11 +36,24 @@ EXTRA_RUNS+=3D$(MULTIARCH_RUNS) %.o: $(CRT_PATH)/%.S $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wa,--noexecstack -c $< -o $@ =20 -# Build and link the tests +# Build and link the multiarch tests %: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) =20 +# Build and link the arch tests +%: $(X86_64_SYSTEM_SRC)/%.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS) + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) + memory: CFLAGS+=3D-DCHECK_UNALIGNED=3D1 +patch-target: CFLAGS+=3D-O0 =20 # Running QEMU_OPTS+=3D-device isa-debugcon,chardev=3Doutput -device isa-debug-exit,= iobase=3D0xf4,iosize=3D0x4 -kernel + +# Add patch-target to ADDITIONAL_PLUGINS_TESTS +ADDITIONAL_PLUGINS_TESTS +=3D patch-target + +run-plugin-patch-target-with-libpatch.so: \ + PLUGIN_ARGS=3D$(COMMA)target=3Dffc0$(COMMA)patch=3D9090$(COMMA)use_hwaddr= =3Dtrue$(COMMA)debug_insns=3Dfalse +run-plugin-patch-target-with-libpatch.so: \ + CHECK_PLUGIN_OUTPUT_COMMAND=3D$(X86_64_SYSTEM_SRC)/validate-patch.py $@.o= ut \ No newline at end of file diff --git a/tests/tcg/x86_64/system/patch-target.c b/tests/tcg/x86_64/syst= em/patch-target.c new file mode 100644 index 0000000000..8a7c0a0ae8 --- /dev/null +++ b/tests/tcg/x86_64/system/patch-target.c @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This test target increments a value 100 times. The patcher converts the + * inc instruction to a nop, so it only increments the value once. + * + */ +#include + +int main(void) +{ + ml_printf("Running test...\n"); +#if defined(__x86_64__) + ml_printf("Testing insn memory read/write...\n"); + unsigned int x =3D 0; + for (int i =3D 0; i < 100; i++) { + asm volatile ( + "inc %[x]" + : [x] "+a" (x) + ); + } + ml_printf("Value: %d\n", x); +#else + #error "This test is only valid for x86_64 architecture." +#endif + return 0; +} diff --git a/tests/tcg/x86_64/system/validate-patch.py b/tests/tcg/x86_64/s= ystem/validate-patch.py new file mode 100755 index 0000000000..700950eae5 --- /dev/null +++ b/tests/tcg/x86_64/system/validate-patch.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# +# validate-patch.py: check the patch applies +# +# This program takes two inputs: +# - the plugin output +# - the binary output +# +# Copyright (C) 2024 +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import sys +from argparse import ArgumentParser + +def main() -> None: + """ + Process the arguments, injest the program and plugin out and + verify they match up and report if they do not. + """ + parser =3D ArgumentParser(description=3D"Validate patch") + parser.add_argument('test_output', + help=3D"The output from the test itself") + parser.add_argument('plugin_output', + help=3D"The output from plugin") + args =3D parser.parse_args() + + with open(args.test_output, 'r') as f: + test_data =3D f.read() + with open(args.plugin_output, 'r') as f: + plugin_data =3D f.read() + if "Value: 1" in test_data: + sys.exit(0) + else: + sys.exit(1) + +if __name__ =3D=3D "__main__": + main() + --=20 2.49.0 From nobody Sun Feb 8 23:32:15 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1749497989; cv=none; d=zohomail.com; s=zohoarc; b=QkJTGO/fSc0uL8askWDswkF5HUpNqJakTQgRhI8aXxcK8HoIbl2//92WHK37P0EMeHvCAze81MIAo6HJx6o10gejyq6iTHAIATf12JPRS0zpr/JSGujeqV36wVj8ocj8qea/0ZfUyB0sm4m9zWwkMDhYyrTGqicoZcuzJK2dV0c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749497989; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Z0nlYktoATC6j3lpIaHBr3lSUsxpIXbgJCeWazuE310=; b=DB7DSetLecEM3sQQBB2x4XFTsTt9No2WrqJ6WuZQWIDKFlU9pXj0WKB3sUU6gincvOyLmifcpDB821mRMFIrSZv70HYk49pQJnnm3i1D2CSnK15V0ZvYekXTayty8r+4+oU/znm0EoP8vINVlPn+4HGSdphIBhTBSU3lTPiHXnw= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749497989463816.8601712941487; Mon, 9 Jun 2025 12:39:49 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOiKg-0007Gu-Bi; Mon, 09 Jun 2025 15:38:59 -0400 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 1uOiKa-0007Ex-Hq for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:52 -0400 Received: from mail-pf1-x432.google.com ([2607:f8b0:4864:20::432]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uOiKX-0004Dq-JG for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:52 -0400 Received: by mail-pf1-x432.google.com with SMTP id d2e1a72fcca58-747ef5996edso3566248b3a.0 for ; Mon, 09 Jun 2025 12:38:49 -0700 (PDT) Received: from shemhazi.lan ([50.46.174.34]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7482b083b03sm6095725b3a.83.2025.06.09.12.38.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 12:38:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749497928; x=1750102728; 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=Z0nlYktoATC6j3lpIaHBr3lSUsxpIXbgJCeWazuE310=; b=Ae8MiGcPL3w+Yp8JZKyZ51nXBsrEnVfiUCV/xHGcooG+4BV/xQTfyDlOrL1utkwc0N RJ4omBQceL9UVi4Ep7PCXWfgJnJTz7UYFzeGexwQ4I8RM++im74j5oI64WYcQBmYQYZ2 Q/V4sp6pBT4qkS2dF5oW7y9cKusb2GvAWAeVvCFVqi0kqBP8Mvr9lIha9qAaaUWpzlNL E0u0vvt0PN8qH6mmgEOifyx0LiRrbOMlso09FCvl9d6eyY0WwsO4rmF73rIVvBYU2Hly oKqx521DK7rQgOnXv3fXap3tfBIV6wMZjHqUGXTjRZZR8LszQpBCAiCCxMAtg3mRL5wF 9w4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749497928; x=1750102728; 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=Z0nlYktoATC6j3lpIaHBr3lSUsxpIXbgJCeWazuE310=; b=LcEcyQJZ5zXH+t70XoU1Qmmg88v/PeTNkXtbhw7mnzH/NJkx5UAoOycFrz60FlWrdT iQrF9yoA4a2bD8w/ri8ufjUYKJmnyMgqNBOSkyCQZ6AqZSeEVvne30A93q8rJiNdn4IK YS128pZ1Ok1J+797WqatiAwGeuSP1raZ5lHaGRCouU+2mywZ13CV86ajBz5GNcD91Lxj G5sZWvDJ+f4/IvuU+m/KZOMB35EZtqHbhV6buhpXSOHcT4+ui139X+Nj1i+sP1F6NP/5 uCvyrpTCQm73N7wZ/wvbpM/KTmuiCfvnDn0eFoVp1Ktyo84Nv3AFMKDhDhpeSZkiEpEs vxAg== X-Gm-Message-State: AOJu0Yx7cRKNC1MDRoI3SiQrV5iznwMjOsDRffpAHuPIj37aUwiQMAgH zBPYPyCq88hpRsqvPt8HtefSTgVn2jjX0T5smN6jtzIUKZ35epV+kKjzf/P4vZjP X-Gm-Gg: ASbGncuQxvsx5up6At8yZXqgowUQrsQGpjPMS/V/2OuPX3l1aILhid3ga4AlBt/WyHT fVbrsYaIQ2RckLELa2Hf4Cizh/JNvB5O9dySA1YcZv0OnKqZBnKKn128RhO1rDPZB5wI0TQDtWm nb8+PxXGzxTTA2WPj207rfcJCQUAEUFhTrKf6E+R1chnxzN1mrweJD7Qy7yOXvvI91XG0StgUGz iu9/D1iPXZfHPVXJmHFkHCGqo+ozVhDQN230qqR/9ScpLebZQZzco+thUOjAq9TqTLISEBWNUeG NCa5wxjxV/gRsgwr/dzwX250VGZ8fCsIhO7px4232HJdeyqhbfiKU+ScJYM3Gg== X-Google-Smtp-Source: AGHT+IFHrDbCBowk8Ld3Jen+9d3bsukHuL0I8tZ2rxxAM3lISOta9lB6leWafZng7dLEyB11SIrNGg== X-Received: by 2002:a05:6a00:3c8c:b0:740:9d6f:a73b with SMTP id d2e1a72fcca58-748280ac433mr17528532b3a.17.1749497927856; Mon, 09 Jun 2025 12:38:47 -0700 (PDT) From: Rowan Hart To: qemu-devel@nongnu.org Cc: Zhao Liu , Eduardo Habkost , Pierrick Bouvier , Richard Henderson , Mahmoud Mandour , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Marcel Apfelbaum , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Yanan Wang , Alexandre Iooss , novafacing Subject: [PATCH v11 7/8] plugins: Add hypercalls plugin and test Date: Mon, 9 Jun 2025 12:38:40 -0700 Message-ID: <20250609193841.348076-8-rowanbhart@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609193841.348076-1-rowanbhart@gmail.com> References: <20250609193841.348076-1-rowanbhart@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::432; envelope-from=rowanbhart@gmail.com; helo=mail-pf1-x432.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, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1749497991740116600 Content-Type: text/plain; charset="utf-8" From: novafacing This patch adds a plugin that implements a simple form of hypercalls from guest code to the plugin by using the register read API. It accepts only one hypercall, which writes a magic value to guest memory. Signed-off-by: Rowan Hart --- tests/tcg/Makefile.target | 1 + tests/tcg/plugins/hypercalls.c | 547 ++++++++++++++++++ tests/tcg/plugins/meson.build | 2 +- tests/tcg/x86_64/Makefile.softmmu-target | 6 +- tests/tcg/x86_64/system/hypercalls-target.c | 40 ++ .../tcg/x86_64/system/validate-hypercalls.py | 40 ++ 6 files changed, 634 insertions(+), 2 deletions(-) create mode 100644 tests/tcg/plugins/hypercalls.c create mode 100644 tests/tcg/x86_64/system/hypercalls-target.c create mode 100755 tests/tcg/x86_64/system/validate-hypercalls.py diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target index 4b709a9d18..5ac9638102 100644 --- a/tests/tcg/Makefile.target +++ b/tests/tcg/Makefile.target @@ -177,6 +177,7 @@ RUN_TESTS+=3D$(EXTRA_RUNS) # exercise things. We can define them on a per-test basis here. run-plugin-%-with-libmem.so: PLUGIN_ARGS=3D$(COMMA)inline=3Dtrue run-plugin-%-with-libpatch.so: PLUGIN_ARGS=3D$(COMMA)target=3Dffffffff$(CO= MMA)patch=3D00000000 +run-plugin-%-with-libhypercalls.so: PLUGIN_ARGS=3D$(COMMA)ignore_unsupport= ed=3Dtrue =20 ifeq ($(filter %-softmmu, $(TARGET)),) run-%: % diff --git a/tests/tcg/plugins/hypercalls.c b/tests/tcg/plugins/hypercalls.c new file mode 100644 index 0000000000..3214bb8ee5 --- /dev/null +++ b/tests/tcg/plugins/hypercalls.c @@ -0,0 +1,547 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This plugin implements a simple hypercall interface for guests (both sy= stem + * and user mode) to call certain operations from the host. + */ +#include "glib.h" +#include "glibconfig.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +QEMU_PLUGIN_EXPORT int qemu_plugin_version =3D QEMU_PLUGIN_VERSION; + +#define AARCH64_N_HYPERCALL_INSNS (28) +#define AARCH64_HYPERCALL_INSN_LEN (4) +#define AARCH64_HYPERCALL_MAX (AARCH64_N_HYPERCALL_INSNS) +#define ARM_N_HYPERCALL_INSNS (12) +#define ARM_HYPERCALL_INSN_LEN (4) +#define ARM_HYPERCALL_MAX (ARM_N_HYPERCALL_INSNS) +#define X86_HYPERCALL_INSN_LEN (2) +#define X86_HYPERCALL_VALUE_BASE (0x4711) +#define X86_HYPERCALL_MAX (0x10000) +#define N_HYPERCALL_ARGS (4) + +static bool ignore_unsupported; + +static struct qemu_plugin_register *get_register(const char *name); +static uint64_t byte_array_to_uint64(GByteArray *buf); + +enum HypercallInsnType { + CONSTANT, + CALLBACK, +}; + + +/* + * Checks an instruction and returns its hypercall number, if it is + * a hypercall instruction, or -1 if it is not. Called at execution + * time. + */ +typedef int32_t (*hypercall_nr_cb)(GByteArray *); + +/* + * Checks an instruction and returns whether it is a hypercall, or -1 if i= t is + * not. Called at execution time. + */ +typedef bool (*is_hypercall_cb)(GByteArray *); + +/* + * Specifies a Hypercall for an architecture: + * + * - Architecture name + * - Whether it is enabled + * - The hypercall instruction + * - The register names to pass the hypercall # and args + */ +struct HypercallSpec { + const bool enabled; + const char *name; + const bool le; + const char *args[N_HYPERCALL_ARGS]; + const hypercall_nr_cb hypercall_nr_cb; + const is_hypercall_cb is_hypercall_cb; +}; + +static int32_t aarch64_hypercall_nr_cb(GByteArray *insn) +{ + if (insn->len !=3D AARCH64_HYPERCALL_INSN_LEN) { + return -1; + } + + static const uint8_t + hypercall_insns[AARCH64_N_HYPERCALL_INSNS][AARCH64_HYPERCALL_INSN_LEN]= =3D { + { 0xaa, 0x4, 0x0, 0x84 }, + { 0xaa, 0x5, 0x0, 0xa5 }, + { 0xaa, 0x6, 0x0, 0xc6 }, + { 0xaa, 0x7, 0x0, 0xe7 }, + { 0xaa, 0x8, 0x1, 0x8 }, + { 0xaa, 0x9, 0x1, 0x29 }, + { 0xaa, 0xa, 0x1, 0x4a }, + { 0xaa, 0xb, 0x1, 0x6b }, + { 0xaa, 0xc, 0x1, 0x8c }, + { 0xaa, 0xd, 0x1, 0xad }, + { 0xaa, 0xe, 0x1, 0xce }, + { 0xaa, 0xf, 0x1, 0xef }, + { 0xaa, 0x10, 0x2, 0x10 }, + { 0xaa, 0x11, 0x2, 0x31 }, + { 0xaa, 0x12, 0x2, 0x52 }, + { 0xaa, 0x13, 0x2, 0x73 }, + { 0xaa, 0x14, 0x2, 0x94 }, + { 0xaa, 0x15, 0x2, 0xb5 }, + { 0xaa, 0x16, 0x2, 0xd6 }, + { 0xaa, 0x17, 0x2, 0xf7 }, + { 0xaa, 0x18, 0x3, 0x18 }, + { 0xaa, 0x19, 0x3, 0x39 }, + { 0xaa, 0x1a, 0x3, 0x5a }, + { 0xaa, 0x1b, 0x3, 0x7b }, + { 0xaa, 0x1c, 0x3, 0x9c }, + { 0xaa, 0x1d, 0x3, 0xbd }, + { 0xaa, 0x1e, 0x3, 0xde }, + { 0xaa, 0x1f, 0x3, 0xff }, + }; + + for (int32_t i =3D 0; i < AARCH64_N_HYPERCALL_INSNS; i++) { + if (!memcmp(hypercall_insns[i], insn->data, insn->len)) { + return i; + } + } + return -1; +} + +static bool aarch64_is_hypercall_cb(GByteArray *insn) +{ + return aarch64_hypercall_nr_cb(insn) < 0; +} + + +static int32_t aarch64_be_hypercall_nr_cb(GByteArray *insn) +{ + if (insn->len !=3D AARCH64_HYPERCALL_INSN_LEN) { + return -1; + } + + static const uint8_t + hypercall_insns[AARCH64_N_HYPERCALL_INSNS][AARCH64_HYPERCALL_INSN_LEN]= =3D { + {0x84, 0x0, 0x4, 0xaa}, + {0xa5, 0x0, 0x5, 0xaa}, + {0xc6, 0x0, 0x6, 0xaa}, + {0xe7, 0x0, 0x7, 0xaa}, + {0x8, 0x1, 0x8, 0xaa}, + {0x29, 0x1, 0x9, 0xaa}, + {0x4a, 0x1, 0xa, 0xaa}, + {0x6b, 0x1, 0xb, 0xaa}, + {0x8c, 0x1, 0xc, 0xaa}, + {0xad, 0x1, 0xd, 0xaa}, + {0xce, 0x1, 0xe, 0xaa}, + {0xef, 0x1, 0xf, 0xaa}, + {0x10, 0x2, 0x10, 0xaa}, + {0x31, 0x2, 0x11, 0xaa}, + {0x52, 0x2, 0x12, 0xaa}, + {0x73, 0x2, 0x13, 0xaa}, + {0x94, 0x2, 0x14, 0xaa}, + {0xb5, 0x2, 0x15, 0xaa}, + {0xd6, 0x2, 0x16, 0xaa}, + {0xf7, 0x2, 0x17, 0xaa}, + {0x18, 0x3, 0x18, 0xaa}, + {0x39, 0x3, 0x19, 0xaa}, + {0x5a, 0x3, 0x1a, 0xaa}, + {0x7b, 0x3, 0x1b, 0xaa}, + {0x9c, 0x3, 0x1c, 0xaa}, + {0xbd, 0x3, 0x1d, 0xaa}, + {0xde, 0x3, 0x1e, 0xaa}, + {0xff, 0x3, 0x1f, 0xaa}, + }; + + for (int32_t i =3D 0; i < AARCH64_N_HYPERCALL_INSNS; i++) { + if (!memcmp(hypercall_insns[i], insn->data, insn->len)) { + return i; + } + } + return -1; +} + +static bool aarch64_be_is_hypercall_cb(GByteArray *insn) +{ + return aarch64_be_hypercall_nr_cb(insn) < 0; +} + + +static int32_t arm_hypercall_nr_cb(GByteArray *insn) +{ + if (insn->len !=3D ARM_HYPERCALL_INSN_LEN) { + return -1; + } + + static const uint8_t + hypercall_insns[ARM_N_HYPERCALL_INSNS][ARM_HYPERCALL_INSN_LEN] =3D { + { 0xe1, 0x84, 0x40, 0x4 }, + { 0xe1, 0x85, 0x50, 0x5 }, + { 0xe1, 0x86, 0x60, 0x6 }, + { 0xe1, 0x87, 0x70, 0x7 }, + { 0xe1, 0x88, 0x80, 0x8 }, + { 0xe1, 0x89, 0x90, 0x9 }, + { 0xe1, 0x8a, 0xa0, 0xa }, + { 0xe1, 0x8b, 0xb0, 0xb }, + { 0xe1, 0x8c, 0xc0, 0xc }, + { 0xe1, 0x8d, 0xd0, 0xd }, + { 0xe1, 0x8e, 0xe0, 0xe }, + { 0xe1, 0x8f, 0xf0, 0xf }, + }; + + for (int32_t i =3D 0; i < ARM_N_HYPERCALL_INSNS; i++) { + if (!memcmp(hypercall_insns[i], insn->data, insn->len)) { + return i; + } + } + return -1; +} + +static bool arm_is_hypercall_cb(GByteArray *insn) +{ + return arm_hypercall_nr_cb(insn) < 0; +} + +static int32_t arm_be_hypercall_nr_cb(GByteArray *insn) +{ + if (insn->len !=3D ARM_HYPERCALL_INSN_LEN) { + return -1; + } + + static const uint8_t + hypercall_insns[ARM_N_HYPERCALL_INSNS][ARM_HYPERCALL_INSN_LEN] =3D { + {0x4, 0x40, 0x84, 0xe1}, + {0x5, 0x50, 0x85, 0xe1}, + {0x6, 0x60, 0x86, 0xe1}, + {0x7, 0x70, 0x87, 0xe1}, + {0x8, 0x80, 0x88, 0xe1}, + {0x9, 0x90, 0x89, 0xe1}, + {0xa, 0xa0, 0x8a, 0xe1}, + {0xb, 0xb0, 0x8b, 0xe1}, + {0xc, 0xc0, 0x8c, 0xe1}, + {0xd, 0xd0, 0x8d, 0xe1}, + {0xe, 0xe0, 0x8e, 0xe1}, + {0xf, 0xf0, 0x8f, 0xe1}, + }; + + for (int32_t i =3D 0; i < ARM_N_HYPERCALL_INSNS; i++) { + if (!memcmp(hypercall_insns[i], insn->data, insn->len)) { + return i; + } + } + return -1; +} + +static bool arm_be_is_hypercall_cb(GByteArray *insn) +{ + return arm_be_hypercall_nr_cb(insn) < 0; +} + +static int32_t x86_64_hypercall_nr_cb(GByteArray *insn) +{ + if (insn->len !=3D X86_HYPERCALL_INSN_LEN) { + return -1; + } + + uint8_t cpuid[] =3D { 0x0f, 0xa2 }; + if (!memcmp(cpuid, insn->data, insn->len)) { + GByteArray *reg =3D g_byte_array_new(); + qemu_plugin_read_register(get_register("rax"), reg); + uint64_t value =3D byte_array_to_uint64(reg); + g_byte_array_free(reg, true); + + if (!(value & X86_HYPERCALL_VALUE_BASE)) { + return -1; + } + + value =3D (value >> 16) & 0xffff; + + if (value >=3D X86_HYPERCALL_MAX) { + return -1; + } + + return (int32_t)value; + } + + return -1; +} + +static bool x86_64_is_hypercall_cb(GByteArray *insn) +{ + if (insn->len !=3D X86_HYPERCALL_INSN_LEN) { + return false; + } + + uint8_t cpuid[] =3D { 0x0f, 0xa2 }; + if (!memcmp(cpuid, insn->data, insn->len)) { + return true; + } + + return false; +} + +static int32_t i386_hypercall_nr_cb(GByteArray *insn) +{ + if (insn->len !=3D X86_HYPERCALL_INSN_LEN) { + return -1; + } + + uint8_t cpuid[] =3D { 0x0f, 0xa2 }; + if (!memcmp(cpuid, insn->data, insn->len)) { + GByteArray *reg =3D g_byte_array_new(); + qemu_plugin_read_register(get_register("eax"), reg); + uint64_t value =3D byte_array_to_uint64(reg); + g_byte_array_free(reg, true); + + if (!(value & X86_HYPERCALL_VALUE_BASE)) { + return -1; + } + + value =3D (value >> 16) & 0xffff; + + if (value >=3D X86_HYPERCALL_MAX) { + return -1; + } + return (int32_t)value; + } + + return -1; + +} + +static bool i386_is_hypercall_cb(GByteArray *insn) +{ + if (insn->len !=3D X86_HYPERCALL_INSN_LEN) { + return false; + } + + uint8_t cpuid[] =3D { 0x0f, 0xa2 }; + if (!memcmp(cpuid, insn->data, insn->len)) { + return true; + } + + return false; + +} + +static const struct HypercallSpec *hypercall_spec; + +static const struct HypercallSpec hypercall_specs[] =3D { + { true, "aarch64", true, { + "x0", "x1", "x2", "x3", + }, aarch64_hypercall_nr_cb, aarch64_is_hypercall_cb + }, + { true, "aarch64_be", false, { + "x0", "x1", "x2", "x3", + }, aarch64_be_hypercall_nr_cb, aarch64_be_is_hypercall_cb + }, + { true, "arm", true, { + "r0", "r1", "r2", "r3", + }, arm_hypercall_nr_cb, arm_is_hypercall_cb + }, + { true, "armeb", false, { + "r0", "r1", "r2", "r3" + }, arm_be_hypercall_nr_cb, arm_be_is_hypercall_cb + }, + { true, "i386", true, { + "edi", "esi", "edx", "ecx" + }, i386_hypercall_nr_cb, i386_is_hypercall_cb + }, + { true, "x86_64", true, { + "rdi", "rsi", "rdx", "rcx" + + }, x86_64_hypercall_nr_cb, x86_64_is_hypercall_cb + }, + { false, NULL, .le =3D false, {NULL, NULL, NULL, NULL}, NULL}, +}; + +static GArray *hypercall_insns; + +/* + * Returns a handle to a register with a given name, or NULL if there is no + * such register. + */ +static struct qemu_plugin_register *get_register(const char *name) +{ + GArray *registers =3D qemu_plugin_get_registers(); + + struct qemu_plugin_register *handle =3D NULL; + + qemu_plugin_reg_descriptor *reg_descriptors =3D + (qemu_plugin_reg_descriptor *)registers->data; + + for (size_t i =3D 0; i < registers->len; i++) { + if (!strcmp(reg_descriptors[i].name, name)) { + handle =3D reg_descriptors[i].handle; + } + } + + g_array_free(registers, true); + + return handle; +} + +/* + * Transforms a byte array with at most 8 entries into a uint64_t + * depending on the target machine's endianness. + */ +static uint64_t byte_array_to_uint64(GByteArray *buf) +{ + uint64_t value =3D 0; + if (hypercall_spec->le) { + for (int i =3D 0; i < buf->len && i < sizeof(uint64_t); i++) { + value |=3D ((uint64_t)buf->data[i]) << (i * 8); + } + } else { + for (int i =3D 0; i < buf->len && i < sizeof(uint64_t); i++) { + value |=3D ((uint64_t)buf->data[i]) << ((buf->len - 1 - i) * 8= ); + } + } + return value; +} + +/* + * Handle a "hypercall" instruction, which has some special meaning for th= is + * plugin. + */ +static void hypercall(unsigned int vcpu_index, void *userdata) +{ + GByteArray *insn_data =3D (GByteArray *)userdata; + int32_t hypercall_nr =3D hypercall_spec->hypercall_nr_cb(insn_data); + + if (hypercall_nr < 0) { + return; + } + + uint64_t args[N_HYPERCALL_ARGS] =3D {0}; + GByteArray *buf =3D g_byte_array_new(); + for (size_t i =3D 0; i < N_HYPERCALL_ARGS; i++) { + g_byte_array_set_size(buf, 0); + struct qemu_plugin_register *reg =3D + get_register(hypercall_spec->args[i]); + qemu_plugin_read_register(reg, buf); + args[i] =3D byte_array_to_uint64(buf); + } + g_byte_array_free(buf, true); + + switch (hypercall_nr) { + /* + * The write hypercall (#0x01) tells the plugin to write random bytes + * of a given size into the memory of the emulated system at a particu= lar + * vaddr + */ + case 1: { + GByteArray *data =3D g_byte_array_new(); + g_byte_array_set_size(data, args[1]); + for (uint64_t i =3D 0; i < args[1]; i++) { + data->data[i] =3D (uint8_t)g_random_int(); + } + qemu_plugin_write_memory_vaddr(args[0], data); + break; + } + default: + break; + } +} + +/* + * Callback on translation of a translation block. + */ +static void vcpu_tb_trans_cb(qemu_plugin_id_t id, struct qemu_plugin_tb *t= b) +{ + for (size_t i =3D 0; i < qemu_plugin_tb_n_insns(tb); i++) { + struct qemu_plugin_insn *insn =3D qemu_plugin_tb_get_insn(tb, i); + GByteArray *insn_data =3D g_byte_array_new(); + size_t insn_len =3D qemu_plugin_insn_size(insn); + g_byte_array_set_size(insn_data, insn_len); + qemu_plugin_insn_data(insn, insn_data->data, insn_data->len); + + if (hypercall_spec->is_hypercall_cb(insn_data)) { + g_array_append_val(hypercall_insns, insn_data); + qemu_plugin_register_vcpu_insn_exec_cb(insn, hypercall, + QEMU_PLUGIN_CB_R_REGS, + (void *)insn_data); + } else { + g_byte_array_free(insn_data, true); + } + + } +} + +static void atexit_cb(qemu_plugin_id_t id, void *userdata) +{ + for (size_t i =3D 0; i < hypercall_insns->len; i++) { + g_byte_array_free(g_array_index(hypercall_insns, GByteArray *, i), + true); + } + + g_array_free(hypercall_insns, true); +} + +static void usage(void) +{ + fprintf(stderr, + "Usage: ,[ignore_unsupported=3D]"); +} + +/* + * Called when the plugin is installed + */ +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, + const qemu_info_t *info, int ar= gc, + char **argv) +{ + if (argc > 1) { + usage(); + return -1; + } + + for (size_t i =3D 0; i < argc; i++) { + char *opt =3D argv[i]; + g_auto(GStrv) tokens =3D g_strsplit(opt, "=3D", 2); + if (g_strcmp0(tokens[0], "ignore_unsupported") =3D=3D 0) { + if (!qemu_plugin_bool_parse(tokens[0], + tokens[1], &ignore_unsupported)) { + fprintf(stderr, + "Failed to parse argument ignore_unsupported\n"); + return -1; + } + } else { + fprintf(stderr, "Unknown argument: %s\n", tokens[0]); + usage(); + return -1; + } + } + + + hypercall_spec =3D &hypercall_specs[0]; + + while (hypercall_spec->name !=3D NULL) { + if (!strcmp(hypercall_spec->name, info->target_name)) { + break; + } + hypercall_spec++; + } + + if (hypercall_spec->name =3D=3D NULL || !hypercall_spec->enabled) { + qemu_plugin_outs("Error: no hypercall spec."); + if (ignore_unsupported) { + return 0; + } + return -1; + } + + hypercall_insns =3D g_array_new(true, true, sizeof(GByteArray *)); + + qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans_cb); + qemu_plugin_register_atexit_cb(id, atexit_cb, NULL); + + return 0; +} diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build index 163042e601..909bf3005a 100644 --- a/tests/tcg/plugins/meson.build +++ b/tests/tcg/plugins/meson.build @@ -1,6 +1,6 @@ t =3D [] if get_option('plugins') - foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall',= 'patch'] + foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'reset', 'syscall',= 'hypercalls', 'patch'] if host_os =3D=3D 'windows' t +=3D shared_module(i, files(i + '.c') + '../../../contrib/plugins/= win32_linker.c', include_directories: '../../../include/qemu', diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Ma= kefile.softmmu-target index 8d3a067c33..8cb2a19461 100644 --- a/tests/tcg/x86_64/Makefile.softmmu-target +++ b/tests/tcg/x86_64/Makefile.softmmu-target @@ -46,14 +46,18 @@ EXTRA_RUNS+=3D$(MULTIARCH_RUNS) =20 memory: CFLAGS+=3D-DCHECK_UNALIGNED=3D1 patch-target: CFLAGS+=3D-O0 +hypercalls-target: CFLAGS+=3D-O0 =20 # Running QEMU_OPTS+=3D-device isa-debugcon,chardev=3Doutput -device isa-debug-exit,= iobase=3D0xf4,iosize=3D0x4 -kernel =20 # Add patch-target to ADDITIONAL_PLUGINS_TESTS ADDITIONAL_PLUGINS_TESTS +=3D patch-target +ADDITIONAL_PLUGINS_TESTS +=3D hypercalls-target =20 run-plugin-patch-target-with-libpatch.so: \ PLUGIN_ARGS=3D$(COMMA)target=3Dffc0$(COMMA)patch=3D9090$(COMMA)use_hwaddr= =3Dtrue$(COMMA)debug_insns=3Dfalse run-plugin-patch-target-with-libpatch.so: \ - CHECK_PLUGIN_OUTPUT_COMMAND=3D$(X86_64_SYSTEM_SRC)/validate-patch.py $@.o= ut \ No newline at end of file + CHECK_PLUGIN_OUTPUT_COMMAND=3D$(X86_64_SYSTEM_SRC)/validate-patch.py $@.o= ut +run-plugin-hypercalls-target-with-libhypercalls.so: \ + CHECK_PLUGIN_OUTPUT_COMMAND=3D$(X86_64_SYSTEM_SRC)/validate-hypercalls.py= $@.out diff --git a/tests/tcg/x86_64/system/hypercalls-target.c b/tests/tcg/x86_64= /system/hypercalls-target.c new file mode 100644 index 0000000000..acb6d695f2 --- /dev/null +++ b/tests/tcg/x86_64/system/hypercalls-target.c @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This test target invokes a hypercall to write the value 0x1337 to a + * variable. + * + */ +#include +#include +#include + +#define _hypercall(num, arg0, arg1, arg2, arg3) \ + unsigned int a __attribute__((unused)) =3D 0; \ + unsigned int b __attribute__((unused)) =3D 0; \ + unsigned int c __attribute__((unused)) =3D 0; \ + unsigned int d __attribute__((unused)) =3D 0; \ + __asm__ __volatile__("cpuid\n\t" \ + : "=3Da"(a), "=3Db"(b), "=3Dc"(c), "=3Dd"(d) = \ + : "a"(num), "D"(arg0), "S"(arg1), \ + "d"(arg2), "c"(arg3)); + +#define hypercall(num, arg0, arg1, arg2, arg3) \ + { \ + unsigned int __num =3D 0x4711 | (num << 16); \ + _hypercall(__num, arg0, arg1, arg2, arg3); \ + } + +int main(void) +{ + uint16_t value =3D 0; + + for (size_t i =3D 0; i < 1000000; i++) { + hypercall(1, &value, sizeof(value), 0, 0); + if (value =3D=3D 0x1337) { + ml_printf("Victory!\n"); + return 0; + } + } + return 0; +} diff --git a/tests/tcg/x86_64/system/validate-hypercalls.py b/tests/tcg/x86= _64/system/validate-hypercalls.py new file mode 100755 index 0000000000..6e7c980706 --- /dev/null +++ b/tests/tcg/x86_64/system/validate-hypercalls.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# +# validate-patch.py: check the patch applies +# +# This program takes two inputs: +# - the plugin output +# - the binary output +# +# Copyright (C) 2024 +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import sys +from argparse import ArgumentParser + +def main() -> None: + """ + Process the arguments, injest the program and plugin out and + verify they match up and report if they do not. + """ + parser =3D ArgumentParser(description=3D"Validate patch") + parser.add_argument('test_output', + help=3D"The output from the test itself") + parser.add_argument('plugin_output', + help=3D"The output from plugin") + args =3D parser.parse_args() + + with open(args.test_output, 'r') as f: + test_data =3D f.read() + with open(args.plugin_output, 'r') as f: + plugin_data =3D f.read() + + if "Victory" in test_data: + sys.exit(0) + else: + sys.exit(1) + +if __name__ =3D=3D "__main__": + main() + --=20 2.49.0 From nobody Sun Feb 8 23:32:15 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1749498077; cv=none; d=zohomail.com; s=zohoarc; b=T+jYPaCKJAkMSBh/V+dPwfOPJSr8t0LfKvhMRulrcmDlKc1XlUNpG5lgxDqGkvSprAxPgFyX+Y3yZ3Iemd+CcPjGtZ+9UXJVWNkdS5J+o2uPUKgAZq198mSAGJ9ERe8whjFoQWxaFgBJM34NlSmIqw8EElI7K1Ie5jang8K8bsw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749498077; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=QaQPhhHbCamu4uXY+C/FHHXcY6DZYaSMK3JVJyC1xcc=; b=DsjItrbl5FQlr5edo0ZyJSDlybUUjI3WylU3BI55oPU5UQj/CjgKhicXjsELaTVK1lWsVDBiQdaYP+p5HBPL3izw5cvbH2ueNugJIrdfcWhQLFKkIe+JP4mF/afGUZH0lA2sxKFjVlFtEmfbbWuh9DlHacDWOyHyOmREP8WIky0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749498077368768.9665424525869; Mon, 9 Jun 2025 12:41:17 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOiKr-0007Kd-Lj; Mon, 09 Jun 2025 15:39:10 -0400 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 1uOiKa-0007Ec-9l for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:52 -0400 Received: from mail-pf1-x436.google.com ([2607:f8b0:4864:20::436]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uOiKY-0004E4-Lg for qemu-devel@nongnu.org; Mon, 09 Jun 2025 15:38:51 -0400 Received: by mail-pf1-x436.google.com with SMTP id d2e1a72fcca58-747c2cc3419so3270235b3a.2 for ; Mon, 09 Jun 2025 12:38:49 -0700 (PDT) Received: from shemhazi.lan ([50.46.174.34]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7482b083b03sm6095725b3a.83.2025.06.09.12.38.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 12:38:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1749497929; x=1750102729; 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=QaQPhhHbCamu4uXY+C/FHHXcY6DZYaSMK3JVJyC1xcc=; b=KKw2SpxKuOnme5pJdZgtWYiRbTt3gHCbAhI0bgVQzy4ZpJ5RsCM3pYfVTgSvUhfKR5 sZLzEf9MlhJsUM5CyE9gkzamxsOAI/jz4pIRSVaRx9rUneNW+/9vDopC/81UZy3db2zj 7V1Z5bZtcQBzvCgMmE5GubXZTNgw/m2BMpyjYaRFAL4kxs3htKkENe0Y9ENQRzBWbGyl qenljlQAbZEZr7bAkxdmqQGuq6xyh9G8aRBvQAXKJOB333cqKCE6CIguWfGSm4SJmE0R 1lcJe1bvLt86wbMalzjZJnxuYQ9caUeBC2ANNW64YbydOlM34MstBjcARDGwZceh4IhV qcgw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749497929; x=1750102729; 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=QaQPhhHbCamu4uXY+C/FHHXcY6DZYaSMK3JVJyC1xcc=; b=X9YjLo//24CxrNL0l/AitTODUlLkNkhCL0r0/2loobFfy877TPsYn8TrVj+Rh4lDLw F4TiKJk+bLOd/c2eU9OoVvaEiysFoX5RUgmySaL/HyWHL07VOn/v/o8TLU/j3+W5sKp3 x2O7/e3YxORfB6BpWl25N9ge1AZyrt/BCECRVUJ4Rm0MmzF5hL9xJP7UnQOFUP2MDIBH 6H/WO9lbaaRU4yXBqTFM2S8YZS9KspbrWqy+y1cBLUCYeQofDggHfMexM36ObByutCIw QEpfnBO/MiXKmiizZIHqbfBcZCGDSs7ZzonP48+3EaPOES24aLyQwrJtNVhEfJv52MwY 2fXg== X-Gm-Message-State: AOJu0Yzllo+xbARShFJT8/71bgd63C+Ravo1snIrhQMbw3JSzaw+9Jf5 +e1ElYTh90VDautUYXza5/KyGVhLz1dyVvU4iQyA7P28lx0Q3uBooUkzSDIEcYKg X-Gm-Gg: ASbGncvoCotIYEf/9wQd4W3nfEZJkdnbnx5YzbPdh5CYCleK4SgAFhG3qn2GfwvYLtI wKvIYa1Bkb24AyiwJAW5YCkHD+blEN4g+5wFhmJ4O1+aRSthwUnRRLahjwynGYMTBWfQ4+fg39Y LBdZBnstdFIl5Aa9cCYZeeuOesQ/5OsXvmtNxKMH/G6LSRTj02oRgbkSYQ0ycZBYPeqJh5+G6hQ Dk6VIVHO2Zg5SczmuvGWaseIWsiHb/ZxBgatC4qshD0ZkuX3ZoXjCiCNyPKvX3RJR957Pq0F2yW SuBR0yx48xUoHg65n4t6sGa2iZwlvTL5X0YLLj/2DnGgclWp+Jc= X-Google-Smtp-Source: AGHT+IHLnBs72YctJJ/JjakmLtFg+rXBlSlZLY1hfg51kulZvo75XuDB65fWcPdrSgCGRyLh6eBWZg== X-Received: by 2002:a05:6a00:2d28:b0:740:6f69:8d94 with SMTP id d2e1a72fcca58-74827cffd46mr22021856b3a.0.1749497928741; Mon, 09 Jun 2025 12:38:48 -0700 (PDT) From: Rowan Hart To: qemu-devel@nongnu.org Cc: Zhao Liu , Eduardo Habkost , Pierrick Bouvier , Richard Henderson , Mahmoud Mandour , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Marcel Apfelbaum , Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Yanan Wang , Alexandre Iooss , novafacing Subject: [PATCH v11 8/8] plugins: Update plugin version and add notes Date: Mon, 9 Jun 2025 12:38:41 -0700 Message-ID: <20250609193841.348076-9-rowanbhart@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609193841.348076-1-rowanbhart@gmail.com> References: <20250609193841.348076-1-rowanbhart@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::436; envelope-from=rowanbhart@gmail.com; helo=mail-pf1-x436.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, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham 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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1749498078595116600 Content-Type: text/plain; charset="utf-8" From: novafacing This patch updates the plugin version to gate new APIs and adds notes describing what has been added. Signed-off-by: Rowan Hart Reviewed-by: Pierrick Bouvier --- include/qemu/qemu-plugin.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h index 5eecdccc67..c450106af1 100644 --- a/include/qemu/qemu-plugin.h +++ b/include/qemu/qemu-plugin.h @@ -65,11 +65,18 @@ typedef uint64_t qemu_plugin_id_t; * * version 4: * - added qemu_plugin_read_memory_vaddr + * + * version 5: + * - added qemu_plugin_write_memory_vaddr + * - added qemu_plugin_read_memory_hwaddr + * - added qemu_plugin_write_memory_hwaddr + * - added qemu_plugin_write_register + * - added qemu_plugin_translate_vaddr */ =20 extern QEMU_PLUGIN_EXPORT int qemu_plugin_version; =20 -#define QEMU_PLUGIN_VERSION 4 +#define QEMU_PLUGIN_VERSION 5 =20 /** * struct qemu_info_t - system information for plugins --=20 2.49.0