[PATCH v4 7/7] tests/tcg/plugins: test register readonly feature

Florian Hofhammer posted 7 patches 1 month, 2 weeks ago
Maintainers: Laurent Vivier <laurent@vivier.eu>, Pierrick Bouvier <pierrick.bouvier@linaro.org>, Brian Cain <brian.cain@oss.qualcomm.com>, "Alex Bennée" <alex.bennee@linaro.org>, Alexandre Iooss <erdnaxe@crans.org>, Mahmoud Mandour <ma.mandourr@gmail.com>, Peter Maydell <peter.maydell@linaro.org>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Aurelien Jarno <aurelien@aurel32.net>, Jiaxun Yang <jiaxun.yang@flygoat.com>, Aleksandar Rikalo <arikalo@gmail.com>, Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>, Artyom Tarasenko <atar4qemu@gmail.com>
There is a newer version of this series
[PATCH v4 7/7] tests/tcg/plugins: test register readonly feature
Posted by Florian Hofhammer 1 month, 2 weeks ago
This commit tests the readonly feature for registers exposed via the
plugin API introduced earlier in the patch series.

Signed-off-by: Florian Hofhammer <florian.hofhammer@epfl.ch>
---
 tests/tcg/plugins/meson.build |  1 +
 tests/tcg/plugins/registers.c | 68 +++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)
 create mode 100644 tests/tcg/plugins/registers.c

diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build
index c5e49753fd..5005aa8dc9 100644
--- a/tests/tcg/plugins/meson.build
+++ b/tests/tcg/plugins/meson.build
@@ -6,6 +6,7 @@ test_plugins = [
 'insn.c',
 'mem.c',
 'patch.c',
+'registers.c',
 'reset.c',
 'syscall.c',
 ]
diff --git a/tests/tcg/plugins/registers.c b/tests/tcg/plugins/registers.c
new file mode 100644
index 0000000000..a7bd692225
--- /dev/null
+++ b/tests/tcg/plugins/registers.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2026, Florian Hofhammer <florian.hofhammer@epfl.ch>
+ *
+ * License: GNU GPL, version 2 or later.
+ *   See the COPYING file in the top-level directory.
+ */
+#include "glib.h"
+#include <inttypes.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+/*
+ * This callback is called when a vCPU is initialized. It tests whether we
+ * successfully read from a register and write value back to it. It also tests
+ * that read-only registers cannot be written to, i.e., we can read a read-only
+ * register but writing to it fails.
+ */
+static void vcpu_init_cb(qemu_plugin_id_t id, unsigned int vcpu_index)
+{
+    g_autoptr(GArray) regs = qemu_plugin_get_registers();
+    g_autoptr(GByteArray) buf = g_byte_array_sized_new(0);
+    bool success = false;
+
+    /* Make sure we can read and write an arbitrary register */
+    qemu_plugin_reg_descriptor *reg_desc = &g_array_index(regs,
+            qemu_plugin_reg_descriptor, 0);
+    g_assert(reg_desc->is_readonly == false);
+    success = qemu_plugin_read_register(reg_desc->handle, buf);
+    g_assert(success);
+    success = qemu_plugin_write_register(reg_desc->handle, buf);
+    g_assert(success);
+
+    /*
+     * Reset the buffer and find a read-only register. On each architecture, at
+     * least the PC should be read-only because it's only supposed to be
+     * modified via the qemu_plugin_set_pc() function.
+     */
+    g_byte_array_set_size(buf, 0);
+    for (size_t i = 0; i < regs->len; i++) {
+        reg_desc = &g_array_index(regs, qemu_plugin_reg_descriptor, i);
+        if (reg_desc->is_readonly) {
+            success = qemu_plugin_read_register(reg_desc->handle, buf);
+            g_assert(success);
+            break;
+        } else {
+            reg_desc = NULL;
+        }
+    }
+    /* Make sure there is a read-only register and we cannot write to it */
+    g_assert(reg_desc != NULL);
+    success = qemu_plugin_write_register(reg_desc->handle, buf);
+    g_assert(!success);
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+                                           const qemu_info_t *info,
+                                           int argc, char **argv)
+{
+    qemu_plugin_register_vcpu_init_cb(id, vcpu_init_cb);
+    return 0;
+}
-- 
2.53.0
Re: [PATCH v4 7/7] tests/tcg/plugins: test register readonly feature
Posted by Alex Bennée 1 month, 2 weeks ago
Florian Hofhammer <florian.hofhammer@epfl.ch> writes:

> This commit tests the readonly feature for registers exposed via the
> plugin API introduced earlier in the patch series.
>
> Signed-off-by: Florian Hofhammer <florian.hofhammer@epfl.ch>

Acked-by: Alex Bennée <alex.bennee@linaro.org>

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro
Re: [PATCH v4 7/7] tests/tcg/plugins: test register readonly feature
Posted by Pierrick Bouvier 1 month, 2 weeks ago
On 2/24/26 7:58 AM, Florian Hofhammer wrote:
> This commit tests the readonly feature for registers exposed via the
> plugin API introduced earlier in the patch series.
> 
> Signed-off-by: Florian Hofhammer <florian.hofhammer@epfl.ch>
> ---
>   tests/tcg/plugins/meson.build |  1 +
>   tests/tcg/plugins/registers.c | 68 +++++++++++++++++++++++++++++++++++
>   2 files changed, 69 insertions(+)
>   create mode 100644 tests/tcg/plugins/registers.c
> 
> diff --git a/tests/tcg/plugins/meson.build b/tests/tcg/plugins/meson.build
> index c5e49753fd..5005aa8dc9 100644
> --- a/tests/tcg/plugins/meson.build
> +++ b/tests/tcg/plugins/meson.build
> @@ -6,6 +6,7 @@ test_plugins = [
>   'insn.c',
>   'mem.c',
>   'patch.c',
> +'registers.c',
>   'reset.c',
>   'syscall.c',
>   ]
> diff --git a/tests/tcg/plugins/registers.c b/tests/tcg/plugins/registers.c
> new file mode 100644
> index 0000000000..a7bd692225
> --- /dev/null
> +++ b/tests/tcg/plugins/registers.c
> @@ -0,0 +1,68 @@
> +/*
> + * Copyright (C) 2026, Florian Hofhammer <florian.hofhammer@epfl.ch>
> + *
> + * License: GNU GPL, version 2 or later.
> + *   See the COPYING file in the top-level directory.
> + */
> +#include "glib.h"
> +#include <inttypes.h>
> +#include <assert.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <stdio.h>
> +
> +#include <qemu-plugin.h>
> +
> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
> +
> +/*
> + * This callback is called when a vCPU is initialized. It tests whether we
> + * successfully read from a register and write value back to it. It also tests
> + * that read-only registers cannot be written to, i.e., we can read a read-only
> + * register but writing to it fails.
> + */
> +static void vcpu_init_cb(qemu_plugin_id_t id, unsigned int vcpu_index)
> +{
> +    g_autoptr(GArray) regs = qemu_plugin_get_registers();
> +    g_autoptr(GByteArray) buf = g_byte_array_sized_new(0);
> +    bool success = false;
> +
> +    /* Make sure we can read and write an arbitrary register */
> +    qemu_plugin_reg_descriptor *reg_desc = &g_array_index(regs,
> +            qemu_plugin_reg_descriptor, 0);
> +    g_assert(reg_desc->is_readonly == false);
> +    success = qemu_plugin_read_register(reg_desc->handle, buf);
> +    g_assert(success);
> +    success = qemu_plugin_write_register(reg_desc->handle, buf);
> +    g_assert(success);
> +
> +    /*
> +     * Reset the buffer and find a read-only register. On each architecture, at
> +     * least the PC should be read-only because it's only supposed to be
> +     * modified via the qemu_plugin_set_pc() function.
> +     */
> +    g_byte_array_set_size(buf, 0);
> +    for (size_t i = 0; i < regs->len; i++) {
> +        reg_desc = &g_array_index(regs, qemu_plugin_reg_descriptor, i);
> +        if (reg_desc->is_readonly) {
> +            success = qemu_plugin_read_register(reg_desc->handle, buf);
> +            g_assert(success);
> +            break;
> +        } else {
> +            reg_desc = NULL;
> +        }
> +    }
> +    /* Make sure there is a read-only register and we cannot write to it */
> +    g_assert(reg_desc != NULL);
> +    success = qemu_plugin_write_register(reg_desc->handle, buf);
> +    g_assert(!success);
> +}
> +
> +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
> +                                           const qemu_info_t *info,
> +                                           int argc, char **argv)
> +{
> +    qemu_plugin_register_vcpu_init_cb(id, vcpu_init_cb);
> +    return 0;
> +}

Looks great, and nice to have a test for this.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>