From nobody Sat Nov 15 14:09:08 2025 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=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1751453139; cv=none; d=zohomail.com; s=zohoarc; b=HeRih0aR4LtI8D5Hci3IJmTEmxr/Mg7JOz+D3w87sKCSjnO43o4bH03ofrON/ckeXFkcnM7kse4ei/ckpvmBKM3w72WMsr8sRDJ7GqikO3RJq1HXaLy6/l1Dt3o9fRGa7eoi1FFOdVNTLTMylIQn6gOg9nQbboYIWKbK/QEQYMo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1751453139; 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=f8Jt4664qtDHEeSxPHU9UkVhjqAuRPFvBiOKbwQQWMA=; b=LGRZfjenIbBc8cjT6/3/rvmd0y/Sl5zePp7soA+2gD/HMCm6c8PGx6nfyIsZJdAKcSuOpdXLSnsJ+gEUlTRoqII0WTX7kEmng9t51Aq7CxvzC48x2BEg+zoF8mtWwIAtd/S088q4tVfLlmpkpI48xL6vTCH2jHU4ooUzoyWuGao= 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 175145313975221.08548304857277; Wed, 2 Jul 2025 03:45:39 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uWuwm-0006lr-QV; Wed, 02 Jul 2025 06:44:12 -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 1uWuwe-0006hP-Ns for qemu-devel@nongnu.org; Wed, 02 Jul 2025 06:44:05 -0400 Received: from mail-ej1-x630.google.com ([2a00:1450:4864:20::630]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1uWuwR-0001Jw-6O for qemu-devel@nongnu.org; Wed, 02 Jul 2025 06:44:03 -0400 Received: by mail-ej1-x630.google.com with SMTP id a640c23a62f3a-ae35f36da9dso859961866b.0 for ; Wed, 02 Jul 2025 03:43:48 -0700 (PDT) Received: from draig.lan ([185.126.160.19]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae353659fdesm1064493566b.69.2025.07.02.03.43.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Jul 2025 03:43:42 -0700 (PDT) Received: from draig.lan (localhost [IPv6:::1]) by draig.lan (Postfix) with ESMTP id AF6555F8F3; Wed, 02 Jul 2025 11:43:37 +0100 (BST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1751453027; x=1752057827; 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=f8Jt4664qtDHEeSxPHU9UkVhjqAuRPFvBiOKbwQQWMA=; b=UdsvrR1xlZ7zPgC0qVtswAUAc93LlAlUxcMSVI19KB1AUwid/0HPGZ94Yle+bBK31j NMFh73VvA93RaWWjrlth0JdHYGTd9/ddbZmVAIZJMWaxQq9eN+jsoF8u48geFa0zQox/ A9Qxe67rsJVw/y/okacBLgPaz6kHK+4LiK1PhYN05xv2LTucyNlWwIZFd0yHeXfs+rIv WVmSDSpmeCy1Od2s3d+FOBxWloLrQNh3Zw5SWfjPEsvjjFAwl5y1gI+YpG0aIsK3uPEO 0NwYd6PvE7MXpsvMII0oEqs1PGTVGS9bZLPU5kFnWXb1LJwDkoxcLwGz1hXLchY2mtuJ IrPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751453027; x=1752057827; 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=f8Jt4664qtDHEeSxPHU9UkVhjqAuRPFvBiOKbwQQWMA=; b=CdxZXY613avgUAFlqMSGN3bMhnBs50HLrKrhZWM2m1np3VizsG8FTBljVtzUylQevQ bE8v+R4Nre0KnanzhWZdXIfXeVDBgaqXVMDe/CrTkfBh79DjY7sZ8KOWd03/fCOsBBoT S3l+UBaa8MD7F7lwt2uCHWmrEkWOPBqcD6JcCry4zBPSMJtFkO7WSAWOg4m/KfjfCCYV dnTGiDVNJh06UO1oxQzXOtqGOUQOIYH79mS6AyGX5nwiP29wdgYukFqckRVnBOa5VvMr jdoGiz2nCphMc36GdP9VUCglS6Xfk1/v4m0kWl4M+XbKpMsGAgzLNeF1o56NC81uHF0n mPmA== X-Gm-Message-State: AOJu0YzFVer2pZgL3cm7sxcHOPgo9Kzlh7Uut88KNRrNRKfYEx0DDCXc Sj3P5zqqWo4kxLruLNBIYFm0LVEYJkvQH1ZNuydYIdUzxyDoxjj9iA7/7E7ANMT+ba0IsJcoED5 7rKQPfxw= X-Gm-Gg: ASbGnctC69hz5BVu6pUojPcFHSKuC4bMskUnUFXmwcl5a5b70BoxDuvP77Xc2ACLTL/ JhG3ByHOAUgr9Qjm8Rz0M2zZ+6alcCR3pdF6AfMFLspiJegArnFJh7NNV/OkQ82wCXe9NqC/SE8 5Vqw0lWftrgjGpTIH9Ej8hnpGjti+ATddOvXsxB6/BwqDaS82cGM5pIfl+TpKB7CySZw66nPAVA ReeJSDhEpupC150F26nugXsBImm7+8rfe4LhA0zV3u6+2++KQ0CmPyVhmU5T4/h4YF0D7k4XnSA yeIONkF1CQXAyWb65IdRH+F1t5/4MTUIZ6mvPkOlKixaj+3UpUjIUhacQrUinnVRrv04TQE5EQ= = X-Google-Smtp-Source: AGHT+IEgwdF3E8PekXYu26dmtcPgYMLJk1M2I5aa/cyngx5k+BHob4iPED2fxkH0QZBYQNqXdvLqGA== X-Received: by 2002:a17:907:da5:b0:ae3:61e8:c6a8 with SMTP id a640c23a62f3a-ae3c29672ffmr237896266b.0.1751453027219; Wed, 02 Jul 2025 03:43:47 -0700 (PDT) From: =?UTF-8?q?Alex=20Benn=C3=A9e?= To: qemu-devel@nongnu.org Cc: Rowan Hart , Pierrick Bouvier , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Alexandre Iooss , Mahmoud Mandour Subject: [PULL 09/15] plugins: Add memory hardware address read/write API Date: Wed, 2 Jul 2025 11:43:30 +0100 Message-ID: <20250702104336.3775206-10-alex.bennee@linaro.org> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250702104336.3775206-1-alex.bennee@linaro.org> References: <20250702104336.3775206-1-alex.bennee@linaro.org> 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=2a00:1450:4864:20::630; envelope-from=alex.bennee@linaro.org; helo=mail-ej1-x630.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, 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 @linaro.org) X-ZM-MESSAGEID: 1751453141048116600 From: Rowan Hart 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 Message-ID: <20250624175351.440780-6-rowanbhart@gmail.com> Signed-off-by: Alex Benn=C3=A9e Message-ID: <20250627112512.1880708-10-alex.bennee@linaro.org> 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.47.2