[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 07/28] qtest: add a QOM object for qtest
From: |
Paolo Bonzini |
Subject: |
[PULL 07/28] qtest: add a QOM object for qtest |
Date: |
Mon, 24 May 2021 18:41:10 +0200 |
The qtest server right now can only be created using the -qtest
and -qtest-log options. Allow an alternative way to create it
using "-object qtest,chardev=...,log=...".
This is part of the long term plan to make more (or all) of
QEMU configurable through QMP and preconfig mode.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
qapi/qom.json | 17 +++++
softmmu/qtest.c | 185 +++++++++++++++++++++++++++++++++++++++++++++---
softmmu/vl.c | 5 +-
3 files changed, 196 insertions(+), 11 deletions(-)
diff --git a/qapi/qom.json b/qapi/qom.json
index 4f48035831..f7ef30f940 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -644,6 +644,21 @@
{ 'struct': 'PrManagerHelperProperties',
'data': { 'path': 'str' } }
+##
+# @QtestProperties:
+#
+# Properties for qtest objects.
+#
+# @chardev: the chardev to be used to receive qtest commands on.
+#
+# @log: the path to a log file
+#
+# Since: 6.0
+##
+{ 'struct': 'QtestProperties',
+ 'data': { 'chardev': 'str',
+ '*log': 'str' } }
+
##
# @RemoteObjectProperties:
#
@@ -769,6 +784,7 @@
'memory-backend-ram',
'pef-guest',
'pr-manager-helper',
+ 'qtest',
'rng-builtin',
'rng-egd',
'rng-random',
@@ -825,6 +841,7 @@
'if': 'defined(CONFIG_LINUX)' },
'memory-backend-ram': 'MemoryBackendProperties',
'pr-manager-helper': 'PrManagerHelperProperties',
+ 'qtest': 'QtestProperties',
'rng-builtin': 'RngProperties',
'rng-egd': 'RngEgdProperties',
'rng-random': 'RngRandomProperties',
diff --git a/softmmu/qtest.c b/softmmu/qtest.c
index 130c366615..72751e1fd8 100644
--- a/softmmu/qtest.c
+++ b/softmmu/qtest.c
@@ -27,6 +27,8 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/cutils.h"
+#include "qapi/qmp/qerror.h"
+#include "qom/object_interfaces.h"
#include CONFIG_DEVICES
#ifdef CONFIG_PSERIES
#include "hw/ppc/spapr_rtas.h"
@@ -34,11 +36,25 @@
#define MAX_IRQ 256
+#define TYPE_QTEST "qtest"
+
+OBJECT_DECLARE_SIMPLE_TYPE(QTest, QTEST)
+
+struct QTest {
+ Object parent;
+
+ bool has_machine_link;
+ char *chr_name;
+ Chardev *chr;
+ CharBackend qtest_chr;
+ char *log;
+};
+
bool qtest_allowed;
static DeviceState *irq_intercept_dev;
static FILE *qtest_log_fp;
-static CharBackend qtest_chr;
+static QTest *qtest;
static GString *inbuf;
static int irq_levels[MAX_IRQ];
static qemu_timeval start_time;
@@ -320,7 +336,7 @@ static void qtest_irq_handler(void *opaque, int n, int
level)
qemu_set_irq(old_irq, level);
if (irq_levels[n] != level) {
- CharBackend *chr = &qtest_chr;
+ CharBackend *chr = &qtest->qtest_chr;
irq_levels[n] = level;
qtest_send_prefix(chr);
qtest_sendf(chr, "IRQ %s %d\n",
@@ -849,18 +865,39 @@ static void qtest_event(void *opaque, QEMUChrEvent event)
break;
}
}
+
void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error
**errp)
{
+ ERRP_GUARD();
Chardev *chr;
+ Object *qtest;
chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
-
if (chr == NULL) {
error_setg(errp, "Failed to initialize device for qtest: \"%s\"",
qtest_chrdev);
return;
}
+ qtest = object_new(TYPE_QTEST);
+ object_property_set_str(qtest, "chardev", "qtest", &error_abort);
+ if (qtest_log) {
+ object_property_set_str(qtest, "log", qtest_log, &error_abort);
+ }
+ object_property_add_child(qdev_get_machine(), "qtest", qtest);
+ user_creatable_complete(USER_CREATABLE(qtest), errp);
+ if (*errp) {
+ object_unparent(qtest);
+ }
+ object_unref(OBJECT(chr));
+ object_unref(qtest);
+}
+
+static bool qtest_server_start(QTest *q, Error **errp)
+{
+ Chardev *chr = q->chr;
+ const char *qtest_log = q->log;
+
if (qtest_log) {
if (strcmp(qtest_log, "none") != 0) {
qtest_log_fp = fopen(qtest_log, "w+");
@@ -869,16 +906,20 @@ void qtest_server_init(const char *qtest_chrdev, const
char *qtest_log, Error **
qtest_log_fp = stderr;
}
- qemu_chr_fe_init(&qtest_chr, chr, errp);
- qemu_chr_fe_set_handlers(&qtest_chr, qtest_can_read, qtest_read,
- qtest_event, NULL, &qtest_chr, NULL, true);
- qemu_chr_fe_set_echo(&qtest_chr, true);
+ if (!qemu_chr_fe_init(&q->qtest_chr, chr, errp)) {
+ return false;
+ }
+ qemu_chr_fe_set_handlers(&q->qtest_chr, qtest_can_read, qtest_read,
+ qtest_event, NULL, &q->qtest_chr, NULL, true);
+ qemu_chr_fe_set_echo(&q->qtest_chr, true);
inbuf = g_string_new("");
if (!qtest_server_send) {
- qtest_server_set_send_handler(qtest_server_char_be_send, &qtest_chr);
+ qtest_server_set_send_handler(qtest_server_char_be_send,
&q->qtest_chr);
}
+ qtest = q;
+ return true;
}
void qtest_server_set_send_handler(void (*send)(void*, const char*),
@@ -890,7 +931,7 @@ void qtest_server_set_send_handler(void (*send)(void*,
const char*),
bool qtest_driver(void)
{
- return qtest_chr.chr != NULL;
+ return qtest && qtest->qtest_chr.chr != NULL;
}
void qtest_server_inproc_recv(void *dummy, const char *buf)
@@ -905,3 +946,129 @@ void qtest_server_inproc_recv(void *dummy, const char
*buf)
g_string_truncate(gstr, 0);
}
}
+
+static void qtest_complete(UserCreatable *uc, Error **errp)
+{
+ QTest *q = QTEST(uc);
+ if (qtest) {
+ error_setg(errp, "Only one instance of qtest can be created");
+ return;
+ }
+ if (!q->chr_name) {
+ error_setg(errp, "No backend specified");
+ return;
+ }
+
+ if (OBJECT(uc)->parent != qdev_get_machine()) {
+ q->has_machine_link = true;
+ object_property_add_const_link(qdev_get_machine(), "qtest",
OBJECT(uc));
+ } else {
+ /* -qtest was used. */
+ }
+
+ qtest_server_start(q, errp);
+}
+
+static void qtest_unparent(Object *obj)
+{
+ QTest *q = QTEST(obj);
+
+ if (qtest == q) {
+ qemu_chr_fe_disconnect(&q->qtest_chr);
+ assert(!qtest_opened);
+ qemu_chr_fe_deinit(&q->qtest_chr, false);
+ if (qtest_log_fp) {
+ fclose(qtest_log_fp);
+ qtest_log_fp = NULL;
+ }
+ qtest = NULL;
+ }
+
+ if (q->has_machine_link) {
+ object_property_del(qdev_get_machine(), "qtest");
+ q->has_machine_link = false;
+ }
+}
+
+static void qtest_set_log(Object *obj, const char *value, Error **errp)
+{
+ QTest *q = QTEST(obj);
+
+ if (qtest == q) {
+ error_setg(errp, QERR_PERMISSION_DENIED);
+ } else {
+ g_free(q->log);
+ q->log = g_strdup(value);
+ }
+}
+
+static char *qtest_get_log(Object *obj, Error **errp)
+{
+ QTest *q = QTEST(obj);
+
+ return g_strdup(q->log);
+}
+
+static void qtest_set_chardev(Object *obj, const char *value, Error **errp)
+{
+ QTest *q = QTEST(obj);
+ Chardev *chr;
+
+ if (qtest == q) {
+ error_setg(errp, QERR_PERMISSION_DENIED);
+ return;
+ }
+
+ chr = qemu_chr_find(value);
+ if (!chr) {
+ error_setg(errp, "Cannot find character device '%s'", value);
+ return;
+ }
+
+ g_free(q->chr_name);
+ q->chr_name = g_strdup(value);
+
+ if (q->chr) {
+ object_unref(q->chr);
+ }
+ q->chr = chr;
+ object_ref(chr);
+}
+
+static char *qtest_get_chardev(Object *obj, Error **errp)
+{
+ QTest *q = QTEST(obj);
+
+ return g_strdup(q->chr_name);
+}
+
+static void qtest_class_init(ObjectClass *oc, void *data)
+{
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
+
+ oc->unparent = qtest_unparent;
+ ucc->complete = qtest_complete;
+
+ object_class_property_add_str(oc, "chardev",
+ qtest_get_chardev, qtest_set_chardev);
+ object_class_property_add_str(oc, "log",
+ qtest_get_log, qtest_set_log);
+}
+
+static const TypeInfo qtest_info = {
+ .name = TYPE_QTEST,
+ .parent = TYPE_OBJECT,
+ .class_init = qtest_class_init,
+ .instance_size = sizeof(QTest),
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_USER_CREATABLE },
+ { }
+ }
+};
+
+static void register_types(void)
+{
+ type_register_static(&qtest_info);
+}
+
+type_init(register_types);
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 93e78469bc..11ac3750d8 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -1758,8 +1758,9 @@ static bool object_create_early(const char *type)
* add one, state the reason in a comment!
*/
- /* Reason: rng-egd property "chardev" */
- if (g_str_equal(type, "rng-egd")) {
+ /* Reason: property "chardev" */
+ if (g_str_equal(type, "rng-egd") ||
+ g_str_equal(type, "qtest")) {
return false;
}
--
2.31.1
- [PULL 11/28] KVM: Create the KVMSlot dirty bitmap on flag changes, (continued)
- [PULL 11/28] KVM: Create the KVMSlot dirty bitmap on flag changes, Paolo Bonzini, 2021/05/24
- [PULL 13/28] KVM: Provide helper to sync dirty bitmap from slot to ramblock, Paolo Bonzini, 2021/05/24
- [PULL 02/28] configure: check for submodules if --with-git-submodules=ignore, Paolo Bonzini, 2021/05/24
- [PULL 09/28] memory: Introduce log_sync_global() to memory listener, Paolo Bonzini, 2021/05/24
- [PULL 01/28] configure: Only clone softfloat-3 repositories if TCG is enabled, Paolo Bonzini, 2021/05/24
- [PULL 22/28] replication: move include out of root directory, Paolo Bonzini, 2021/05/24
- [PULL 19/28] tests/qtest/fuzz: Fix build failure, Paolo Bonzini, 2021/05/24
- [PULL 18/28] KVM: Dirty ring support, Paolo Bonzini, 2021/05/24
- [PULL 20/28] meson: Set implicit_include_directories to false, Paolo Bonzini, 2021/05/24
- [PULL 25/28] doc: Add notes about -mon option mode=control argument., Paolo Bonzini, 2021/05/24
- [PULL 07/28] qtest: add a QOM object for qtest,
Paolo Bonzini <=
- [PULL 27/28] hw/scsi: Fix sector translation bug in scsi_unmap_complete_noio, Paolo Bonzini, 2021/05/24
- [PULL 26/28] configure: Avoid error messages about missing *-config-*.h files, Paolo Bonzini, 2021/05/24
- [PULL 28/28] gitlab-ci: use --meson=git for CFI jobs, Paolo Bonzini, 2021/05/24
- [PULL 17/28] KVM: Disable manual dirty log when dirty ring enabled, Paolo Bonzini, 2021/05/24
- [PULL 05/28] i386/cpu: Expose AVX_VNNI instruction to guest, Paolo Bonzini, 2021/05/24
- [PULL 14/28] KVM: Simplify dirty log sync in kvm_set_phys_mem, Paolo Bonzini, 2021/05/24
- [PULL 15/28] KVM: Cache kvm slot dirty bitmap size, Paolo Bonzini, 2021/05/24
- [PULL 24/28] qemu-config: load modules when instantiating option groups, Paolo Bonzini, 2021/05/24
- [PULL 16/28] KVM: Add dirty-ring-size property, Paolo Bonzini, 2021/05/24
- [PULL 23/28] vl: allow not specifying size in -m when using -M memory-backend, Paolo Bonzini, 2021/05/24