To keep the MCD JSON protocol separate from QMP, a custom monitor has been implemented in mcd_monitor.c which can be run in parallel to the QMP monitor. It is responsible for handling the JSON communication and for dispatching the corresponding functions in mcd_stub.c The MCD server stub will call the corresponding server functions.
To start the MCD monitor, configure QEMU with --enable-mcd and start it with the -mcd option. Signed-off-by: Mario Fleischmann <mario.fleischm...@lauterbach.com> --- MAINTAINERS | 1 + docs/interop/mcd.rst | 2 + include/exec/mcdstub.h | 17 ++++++++ mcd/mcd_monitor.c | 89 ++++++++++++++++++++++++++++++++++++++++++ mcd/mcd_stub.c | 11 ++++++ mcd/meson.build | 4 +- qemu-options.hx | 11 ++++++ system/vl.c | 13 ++++++ 8 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 include/exec/mcdstub.h create mode 100644 mcd/mcd_monitor.c create mode 100644 mcd/mcd_stub.c diff --git a/MAINTAINERS b/MAINTAINERS index 7c085dc..159a38f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3126,6 +3126,7 @@ S: Maintained F: mcd/* F: docs/interop/mcd.rst F: qapi/mcd.json +F: include/exec/mcdstub.h Memory API M: Paolo Bonzini <pbonz...@redhat.com> diff --git a/docs/interop/mcd.rst b/docs/interop/mcd.rst index 13e81df..860fa8d 100644 --- a/docs/interop/mcd.rst +++ b/docs/interop/mcd.rst @@ -52,6 +52,8 @@ has been added to implement a remote procedure call mechanism. Each function within the API corresponds to one QAPI command, ensuring a one-to-one mapping between the API's functions and the QAPI commands. +Use the option ``-mcd dev`` to start MCD's QAPI monitor. + QAPI Reference -------------- diff --git a/include/exec/mcdstub.h b/include/exec/mcdstub.h new file mode 100644 index 0000000..0513616 --- /dev/null +++ b/include/exec/mcdstub.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef MCDSTUB_H +#define MCDSTUB_H + +#include "qemu/osdep.h" +#include "qapi/error.h" + +bool mcd_monitor_start(const char *device, Error **errp); + +#endif /* MCDSTUB_H */ diff --git a/mcd/mcd_monitor.c b/mcd/mcd_monitor.c new file mode 100644 index 0000000..7ee3eba --- /dev/null +++ b/mcd/mcd_monitor.c @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * mcdmonitor - MCD QAPI protocol handler + * + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "exec/mcdstub.h" +#include "qobject/qdict.h" +#include "qobject/qjson.h" +#include "mcd/mcd-qapi-init-commands.h" +#include "mcd/mcd-qapi-commands.h" +#include "monitor/monitor-internal.h" + +typedef struct { + Monitor mon; + JSONMessageParser parser; +} MonitorMCD; + +static QmpCommandList qapi_commands; +static MonitorMCD mcd_mon; + +static int mcd_monitor_can_read(void *opaque) +{ + return true; +} + +static void mcd_monitor_read(void *opaque, const uint8_t *buf, int size) +{ + json_message_parser_feed(&mcd_mon.parser, (const char *) buf, size); +} + +static void mcd_monitor_handle_chr_event(void *opaque, QEMUChrEvent event) +{ + switch (event) { + default: + /* Ignore */ + break; + } +} + +static void handle_mcd_command(void *opaque, QObject *req, Error *err) +{ + QDict *rsp = qmp_dispatch(&qapi_commands, req, false, &mcd_mon.mon); + const QObject *data = QOBJECT(rsp); + GString *json = qobject_to_json_pretty(data, false); + assert(json != NULL); + g_string_append_c(json, '\n'); + monitor_puts(&mcd_mon.mon, json->str); + g_string_free(json, true); +} + +static void mcd_monitor_init(Chardev *chr, Error **errp) +{ + if (!qemu_chr_fe_init(&mcd_mon.mon.chr, chr, errp)) { + return; + } + qemu_chr_fe_set_echo(&mcd_mon.mon.chr, true); + + /* For now, don't use the I/O thread */ + monitor_data_init(&mcd_mon.mon, true, false, false); + + json_message_parser_init(&mcd_mon.parser, handle_mcd_command, + &mcd_mon.mon, NULL); + + qemu_chr_fe_set_handlers(&mcd_mon.mon.chr, mcd_monitor_can_read, + mcd_monitor_read, mcd_monitor_handle_chr_event, + NULL, &mcd_mon.mon, NULL, true); +} + +bool mcd_monitor_start(const char *device, Error **errp) +{ + Chardev *chr = qemu_chr_new_noreplay("mcd", device, true, NULL); + if (!chr) { + error_setg(errp, "mcdstub: couldn't create Chardev"); + return false; + } + mcd_monitor_init(chr, errp); + return true; +} + +static void __attribute__((__constructor__)) mcd_monitor_init_commands(void) +{ + mcd_qmp_init_marshal(&qapi_commands); +} diff --git a/mcd/mcd_stub.c b/mcd/mcd_stub.c new file mode 100644 index 0000000..de679a4 --- /dev/null +++ b/mcd/mcd_stub.c @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * mcdstub - Conversion of MCD QAPI requests to MCD server function calls + * + * Copyright (c) 2025 Lauterbach GmbH + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "mcd_api.h" diff --git a/mcd/meson.build b/mcd/meson.build index d62a625..191f0cc 100644 --- a/mcd/meson.build +++ b/mcd/meson.build @@ -28,7 +28,9 @@ mcd_ss = ss.source_set() mcd_ss.add(mcd_qapi_files.to_list()) mcd_ss.add(files( - 'mcd_server.c')) + 'mcd_server.c', + 'mcd_stub.c', + 'mcd_monitor.c')) mcd_ss = mcd_ss.apply({}) diff --git a/qemu-options.hx b/qemu-options.hx index dc694a9..2164ad3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4724,6 +4724,17 @@ SRST (see the :ref:`GDB usage` chapter in the System Emulation Users Guide). ERST + +#ifdef CONFIG_MCD +DEF("mcd", HAS_ARG, QEMU_OPTION_mcd, \ + "-mcd dev accept MCD connection on 'dev'\n", + QEMU_ARCH_ALL) +SRST +``-mcd dev`` + Start the MCD QAPI monitor and accept connections on device 'dev'. +ERST +#endif + DEF("d", HAS_ARG, QEMU_OPTION_d, \ "-d item1,... enable logging of specified items (use '-d help' for a list of log items)\n", QEMU_ARCH_ALL) diff --git a/system/vl.c b/system/vl.c index 520956f..73dc786 100644 --- a/system/vl.c +++ b/system/vl.c @@ -71,6 +71,9 @@ #include "system/numa.h" #include "system/hostmem.h" #include "exec/gdbstub.h" +#ifdef CONFIG_MCD +#include "exec/mcdstub.h" +#endif #include "gdbstub/enums.h" #include "qemu/timer.h" #include "chardev/char.h" @@ -1280,6 +1283,7 @@ struct device_config { DEV_PARALLEL, /* -parallel */ DEV_DEBUGCON, /* -debugcon */ DEV_GDB, /* -gdb, -s */ + DEV_MCD, /* -mcd */ DEV_SCLP, /* s390 sclp */ } type; const char *cmdline; @@ -2789,6 +2793,10 @@ static bool qemu_machine_creation_done(Error **errp) foreach_device_config_or_exit(DEV_GDB, gdbserver_start); +#ifdef CONFIG_MCD + foreach_device_config_or_exit(DEV_MCD, mcd_monitor_start); +#endif + if (!vga_interface_created && !default_vga && vga_interface_type != VGA_NONE) { warn_report("A -vga option was passed but this machine " @@ -3150,6 +3158,11 @@ void qemu_init(int argc, char **argv) case QEMU_OPTION_gdb: add_device_config(DEV_GDB, optarg); break; +#ifdef CONFIG_MCD + case QEMU_OPTION_mcd: + add_device_config(DEV_MCD, optarg); + break; +#endif case QEMU_OPTION_L: if (is_help_option(optarg)) { list_data_dirs = true; -- 2.34.1