diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2021-05-26 21:05:35 +0100 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2021-05-26 21:05:36 +0100 |
| commit | 8385235ba99c53d1187658f2fc289b953a8090b1 (patch) | |
| tree | a2ec373b64416a1213aef5e314a16ab086fd45bd /softmmu/qtest.c | |
| parent | 2ab2dad01f6dc3667c0d53d2b1ba46b511031207 (diff) | |
| parent | 7cf333a37260c4aafa465453adc8e073e408967e (diff) | |
| download | focaccia-qemu-8385235ba99c53d1187658f2fc289b953a8090b1.tar.gz focaccia-qemu-8385235ba99c53d1187658f2fc289b953a8090b1.zip | |
Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging
* submodule cleanups (Philippe, myself) * tiny step towards a usable preconfig mode (myself) * Kconfig and LOCK_GUARD cleanups (philippe) * new x86 CPUID feature (Yang Zhong) * "-object qtest" support (myself) * Dirty ring support for KVM (Peter) * Fixes for 6.0 command line parsing breakage (myself) * Fix for macOS 11.3 SDK (Katsuhiro) # gpg: Signature made Wed 26 May 2021 13:50:12 BST # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini-gitlab/tags/for-upstream: (28 commits) gitlab-ci: use --meson=git for CFI jobs hw/scsi: Fix sector translation bug in scsi_unmap_complete_noio configure: Avoid error messages about missing *-config-*.h files doc: Add notes about -mon option mode=control argument. qemu-config: load modules when instantiating option groups vl: allow not specifying size in -m when using -M memory-backend replication: move include out of root directory remove qemu-options* from root directory meson: Set implicit_include_directories to false tests/qtest/fuzz: Fix build failure KVM: Dirty ring support KVM: Disable manual dirty log when dirty ring enabled KVM: Add dirty-ring-size property KVM: Cache kvm slot dirty bitmap size KVM: Simplify dirty log sync in kvm_set_phys_mem KVM: Provide helper to sync dirty bitmap from slot to ramblock KVM: Provide helper to get kvm dirty log KVM: Create the KVMSlot dirty bitmap on flag changes KVM: Use a big lock to replace per-kml slots_lock memory: Introduce log_sync_global() to memory listener ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'softmmu/qtest.c')
| -rw-r--r-- | softmmu/qtest.c | 185 |
1 files changed, 176 insertions, 9 deletions
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); |