From: novafacing <rowanbhart@gmail.com>
---
include/qemu/qemu-plugin.h | 116 +++++++++++++++++++++++++++++++++----
plugins/api.c | 66 ++++++++++++++++++++-
2 files changed, 168 insertions(+), 14 deletions(-)
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index 0fba36ae02..b812593e7f 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
+ *
*/
extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
-#define QEMU_PLUGIN_VERSION 4
+#define QEMU_PLUGIN_VERSION 5
/**
* struct qemu_info_t - system information for plugins
@@ -255,8 +262,6 @@ typedef struct {
* @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,
@@ -893,6 +898,41 @@ typedef struct {
QEMU_PLUGIN_API
GArray *qemu_plugin_get_registers(void);
+/**
+ * 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_W_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 address
*
@@ -916,20 +956,72 @@ bool qemu_plugin_read_memory_vaddr(uint64_t addr,
GByteArray *data, size_t len);
/**
- * qemu_plugin_read_register() - read register for current vCPU
+ * qemu_plugin_write_memory_vaddr() - write to memory using a virtual address
*
- * @handle: a @qemu_plugin_reg_handle handle
- * @buf: A GByteArray for the data owned by the plugin
+ * @addr: A virtual address to write to
+ * @data: A byte array containing the data to write
*
- * This function is only available in a context that register read access is
- * explicitly requested via the QEMU_PLUGIN_CB_R_REGS flag.
+ * The contents of @data will be written to memory starting at the virtual
+ * address @addr.
*
- * Returns the size of the read register. The content of @buf is in target byte
- * order. On failure returns -1.
+ * This function does not guarantee consistency of writes, nor does it ensure
+ * that pending writes are flushed either before or after the write takes
+ * place, so callers should take care when calling this function in plugin
+ * callbacks to avoid depending on the existence of data written using this
+ * function which may be overwritten afterward.
+ *
+ * Returns true on success and false on failure.
*/
QEMU_PLUGIN_API
-int qemu_plugin_read_register(struct qemu_plugin_register *handle,
- GByteArray *buf);
+bool qemu_plugin_write_memory_vaddr(uint64_t addr,
+ GByteArray *data);
+
+/**
+ * qemu_plugin_read_memory_vaddr() - read from memory using a hardware address
+ *
+ * @addr: A virtual 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 starting at @addr and stored into @data. If @data
+ * is not large enough to hold @len bytes, it will be expanded to the necessary
+ * size, reallocating 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 use
+ * the memory callback API instead.
+ *
+ * This function is only valid for softmmu targets.
+ *
+ * Returns true on success and false on failure.
+ */
+QEMU_PLUGIN_API
+bool qemu_plugin_read_memory_hwaddr(uint64_t addr,
+ GByteArray *data, size_t len);
+
+/**
+ * qemu_plugin_write_memory_vaddr() - write to memory using a hardware address
+ *
+ * @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 hardware
+ * address @addr.
+ *
+ * This function does not guarantee consistency of writes, nor does it ensure
+ * that pending writes are flushed either before or after the write takes
+ * place, so callers should take care when calling this function in plugin
+ * callbacks to avoid depending on the existence of data written using this
+ * function which may be overwritten afterward.
+ *
+ * This function is only valid for softmmu targets.
+ *
+ * Returns true on success and false on failure.
+ */
+QEMU_PLUGIN_API
+bool qemu_plugin_write_memory_hwaddr(uint64_t addr,
+ GByteArray *data);
/**
* qemu_plugin_scoreboard_new() - alloc a new scoreboard
diff --git a/plugins/api.c b/plugins/api.c
index 24ea64e2de..4a84cf4dfe 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -560,6 +560,24 @@ GArray *qemu_plugin_get_registers(void)
return create_register_handles(regs);
}
+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 == 0) {
+ return 0;
+ }
+
+ return gdb_write_register(current_cpu, buf->data, GPOINTER_TO_INT(reg) - 1);
+}
+
bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
{
g_assert(current_cpu);
@@ -580,13 +598,57 @@ bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
return true;
}
-int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
+bool qemu_plugin_write_memory_vaddr(vaddr addr, GByteArray *data)
{
g_assert(current_cpu);
- return gdb_read_register(current_cpu, buf, GPOINTER_TO_INT(reg) - 1);
+ if (data->len == 0) {
+ return false;
+ }
+
+ int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
+ data->len, true);
+
+ if (result < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+bool qemu_plugin_read_memory_hwaddr(hwaddr addr, GByteArray *data, size_t len)
+{
+#ifdef CONFIG_SOFTMMU
+ if (len == 0) {
+ return false;
+ }
+
+ g_byte_array_set_size(data, len);
+
+ cpu_physical_memory_rw(addr, data->data, data->len, false);
+
+ return true;
+#else
+ return false;
+#endif
}
+bool qemu_plugin_write_memory_hwaddr(hwaddr addr, GByteArray *data)
+{
+#ifdef CONFIG_SOFTMMU
+ if (data->len == 0) {
+ return false;
+ }
+
+ cpu_physical_memory_rw(addr, data->data, data->len, true);
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+
struct qemu_plugin_scoreboard *qemu_plugin_scoreboard_new(size_t element_size)
{
return plugin_scoreboard_new(element_size);
--
2.46.1
Rowan Hart <rowanbhart@gmail.com> writes: > From: novafacing <rowanbhart@gmail.com> > > --- > include/qemu/qemu-plugin.h | 116 +++++++++++++++++++++++++++++++++---- > plugins/api.c | 66 ++++++++++++++++++++- > 2 files changed, 168 insertions(+), 14 deletions(-) > > diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h > index 0fba36ae02..b812593e7f 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 > + * > */ In the next version please split up the API additions to make it easier to review. For now w.r.t. hwaddr I refer to: Subject: Re: [PATCH 1/1] plugins: add API to read guest CPU memory from hwaddr In-Reply-To: <20240828063224.291503-2-rowanbhart@gmail.com> (Rowan Hart's message of "Tue, 27 Aug 2024 23:32:24 -0700") References: <20240828063224.291503-1-rowanbhart@gmail.com> <20240828063224.291503-2-rowanbhart@gmail.com> Date: Thu, 09 Jan 2025 11:38:48 +0000 Message-ID: <877c749pyv.fsf@draig.linaro.org> -- Alex Bennée Virtualisation Tech Lead @ Linaro
© 2016 - 2026 Red Hat, Inc.