master
c 79 lines 2.68 KB
Raw
1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * Copyright (C) 2026, Florian Hofhammer <florian.hofhammer@epfl.ch>
5 */
6 #include "glib.h"
7 #include <inttypes.h>
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <stdio.h>
13
14 #include <qemu-plugin.h>
15
16 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
17
18 /*
19 * This plugin tests whether we can read and write registers via the plugin
20 * API. We try to just read/write a single register, as some architectures have
21 * registers that cannot be written to, which would fail the test.
22 * See: https://lists.gnu.org/archive/html/qemu-devel/2026-02/msg07025.html
23 */
24 static void vcpu_init_cb(unsigned int vcpu_index, void *userdata)
25 {
26 g_autoptr(GArray) regs = qemu_plugin_get_registers();
27 g_assert(regs != NULL);
28 g_autoptr(GByteArray) buf = g_byte_array_sized_new(0);
29 qemu_plugin_reg_descriptor *reg_desc = NULL;
30 bool success = false;
31
32 /* Make sure we can read and write a register not marked as readonly */
33 for (size_t i = 0; i < regs->len; i++) {
34 reg_desc = &g_array_index(regs, qemu_plugin_reg_descriptor, i);
35 if (!reg_desc->is_readonly) {
36 g_byte_array_set_size(buf, 0);
37 success = qemu_plugin_read_register(reg_desc->handle, buf);
38 g_assert(success);
39 g_assert(buf->len > 0);
40 success = qemu_plugin_write_register(reg_desc->handle, buf);
41 g_assert(success);
42 break;
43 } else {
44 reg_desc = NULL;
45 }
46 }
47 g_assert(regs->len == 0 || reg_desc != NULL);
48
49 /*
50 * Check whether we can still read a read-only register. On each
51 * architecture, at least the PC should be read-only because it's only
52 * supposed to be modified via the qemu_plugin_set_pc() function.
53 */
54 for (size_t i = 0; i < regs->len; i++) {
55 reg_desc = &g_array_index(regs, qemu_plugin_reg_descriptor, i);
56 if (reg_desc->is_readonly) {
57 g_byte_array_set_size(buf, 0);
58 success = qemu_plugin_read_register(reg_desc->handle, buf);
59 g_assert(success);
60 g_assert(buf->len > 0);
61 break;
62 } else {
63 reg_desc = NULL;
64 }
65 }
66 g_assert(regs->len == 0 || reg_desc != NULL);
67 /*
68 * Note: we currently do not test whether the read-only register can be
69 * written to, because doing so would throw an assert in the plugin API.
70 */
71 }
72
73 QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
74 const qemu_info_t *info,
75 int argc, char **argv)
76 {
77 qemu_plugin_register_vcpu_init_cb(id, vcpu_init_cb, NULL);
78 return 0;
79 }