[PATCH v2 37/37] MAINTAINERS: update D-Bus section

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 MAINTAINERS | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 50435b8d2f..b429afba33 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2839,11 +2839,15 @@ D-Bus
 M: Marc-André Lureau 
 S: Maintained
 F: backends/dbus-vmstate.c
-F: tests/dbus-vmstate*
+F: ui/dbus*
+F: audio/dbus*
 F: util/dbus.c
+F: include/ui/dbus*
 F: include/qemu/dbus.h
-F: docs/interop/dbus.rst
-F: docs/interop/dbus-vmstate.rst
+F: docs/interop/dbus*
+F: docs/sphinx/dbus*
+F: docs/sphinx/fakedbusdoc.py
+F: tests/qtest/dbus*
 
 Seccomp
 M: Eduardo Otubo 
-- 
2.33.0.721.g106298f7f9




[PATCH v2 36/37] ui/dbus: register D-Bus VC handler

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Export the default consoles over the D-Bus chardev.

Signed-off-by: Marc-André Lureau 
---
 ui/dbus.c | 53 +
 1 file changed, 53 insertions(+)

diff --git a/ui/dbus.c b/ui/dbus.c
index 38d6ccc607..97248ceadb 100644
--- a/ui/dbus.c
+++ b/ui/dbus.c
@@ -352,6 +352,57 @@ dbus_display_class_init(ObjectClass *oc, void *data)
get_gl_mode, set_gl_mode);
 }
 
+#define TYPE_CHARDEV_VC "chardev-vc"
+
+typedef struct DBusVCClass {
+DBusChardevClass parent_class;
+
+void (*parent_parse)(QemuOpts *opts, ChardevBackend *b, Error **errp);
+} DBusVCClass;
+
+DECLARE_CLASS_CHECKERS(DBusVCClass, DBUS_VC,
+   TYPE_CHARDEV_VC)
+
+static void
+dbus_vc_parse(QemuOpts *opts, ChardevBackend *backend,
+  Error **errp)
+{
+DBusVCClass *klass = DBUS_VC_CLASS(object_class_by_name(TYPE_CHARDEV_VC));
+const char *name = qemu_opt_get(opts, "name");
+const char *id = qemu_opts_id(opts);
+
+if (name == NULL) {
+name = "";
+if (g_str_has_prefix(id, "compat_monitor")) {
+name = "org.qemu.monitor.hmp.0";
+}
+if (g_str_has_prefix(id, "serial")) {
+name = "org.qemu.console.serial.0";
+}
+if (!qemu_opt_set(opts, "name", name, errp)) {
+return;
+}
+}
+
+klass->parent_parse(opts, backend, errp);
+}
+
+static void
+dbus_vc_class_init(ObjectClass *oc, void *data)
+{
+DBusVCClass *klass = DBUS_VC_CLASS(oc);
+ChardevClass *cc = CHARDEV_CLASS(oc);
+
+klass->parent_parse = cc->parse;
+cc->parse = dbus_vc_parse;
+}
+
+static const TypeInfo dbus_vc_type_info = {
+.name = TYPE_CHARDEV_VC,
+.parent = TYPE_CHARDEV_DBUS,
+.class_init = dbus_vc_class_init,
+};
+
 static void
 early_dbus_init(DisplayOptions *opts)
 {
@@ -365,6 +416,8 @@ early_dbus_init(DisplayOptions *opts)
 
 display_opengl = 1;
 }
+
+type_register(_vc_type_info);
 }
 
 static void
-- 
2.33.0.721.g106298f7f9




[PATCH v2 35/37] ui/dbus: add chardev backend & interface

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Add a new chardev backend which allows D-Bus client to handle the
chardev stream & events.

Signed-off-by: Marc-André Lureau 
---
 qapi/char.json|  27 
 include/chardev/char-socket.h |   2 +
 include/qemu/dbus.h   |   5 +
 ui/dbus.h |  44 +
 ui/dbus-chardev.c | 296 ++
 ui/dbus.c |  26 +++
 ui/dbus-display1.xml  |  75 +
 ui/meson.build|   1 +
 8 files changed, 476 insertions(+)
 create mode 100644 ui/dbus-chardev.c

diff --git a/qapi/char.json b/qapi/char.json
index f5133a5eeb..6ed424d07c 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -358,6 +358,20 @@
   'base': 'ChardevCommon',
   'if': 'CONFIG_SPICE' }
 
+##
+# @ChardevDBus:
+#
+# Configuration info for DBus chardevs.
+#
+# @name: name of the channel (following docs/spice-port-fqdn.txt)
+#
+# Since: 6.2
+##
+{ 'struct': 'ChardevDBus',
+  'data': { 'name': 'str' },
+  'base': 'ChardevCommon',
+  'if': 'CONFIG_DBUS_DISPLAY' }
+
 ##
 # @ChardevVC:
 #
@@ -422,6 +436,7 @@
 # @spicevmc: Since 1.5
 # @spiceport: Since 1.5
 # @qemu-vdagent: Since 6.1
+# @dbus: Since 6.2
 # @vc: v1.5
 # @ringbuf: Since 1.6
 # @memory: Since 1.5
@@ -447,6 +462,7 @@
 { 'name': 'spicevmc', 'if': 'CONFIG_SPICE' },
 { 'name': 'spiceport', 'if': 'CONFIG_SPICE' },
 { 'name': 'qemu-vdagent', 'if': 'CONFIG_SPICE_PROTOCOL' },
+{ 'name': 'dbus', 'if': 'CONFIG_DBUS_DISPLAY' },
 'vc',
 'ringbuf',
 # next one is just for compatibility
@@ -535,6 +551,15 @@
   'data': { 'data': 'ChardevQemuVDAgent' },
   'if': 'CONFIG_SPICE_PROTOCOL' }
 
+##
+# @ChardevDBusWrapper:
+#
+# Since: 6.2
+##
+{ 'struct': 'ChardevDBusWrapper',
+  'data': { 'data': 'ChardevDBus' },
+  'if': 'CONFIG_DBUS_DISPLAY' }
+
 ##
 # @ChardevVCWrapper:
 #
@@ -582,6 +607,8 @@
'if': 'CONFIG_SPICE' },
 'qemu-vdagent': { 'type': 'ChardevQemuVDAgentWrapper',
   'if': 'CONFIG_SPICE_PROTOCOL' },
+'dbus': { 'type': 'ChardevDBusWrapper',
+  'if': 'CONFIG_DBUS_DISPLAY' },
 'vc': 'ChardevVCWrapper',
 'ringbuf': 'ChardevRingbufWrapper',
 # next one is just for compatibility
diff --git a/include/chardev/char-socket.h b/include/chardev/char-socket.h
index 1a9274f2e3..6b6e2ceba1 100644
--- a/include/chardev/char-socket.h
+++ b/include/chardev/char-socket.h
@@ -43,6 +43,8 @@ typedef enum {
 TCP_CHARDEV_STATE_CONNECTED,
 } TCPChardevState;
 
+typedef ChardevClass SocketChardevClass;
+
 struct SocketChardev {
 Chardev parent;
 QIOChannel *ioc; /* Client I/O channel */
diff --git a/include/qemu/dbus.h b/include/qemu/dbus.h
index c0cbb1ca44..08f00dfd53 100644
--- a/include/qemu/dbus.h
+++ b/include/qemu/dbus.h
@@ -12,6 +12,11 @@
 
 #include 
 
+#include "qom/object.h"
+#include "chardev/char.h"
+#include "qemu/notify.h"
+#include "qemu/typedefs.h"
+
 /* glib/gio 2.68 */
 #define DBUS_METHOD_INVOCATION_HANDLED TRUE
 #define DBUS_METHOD_INVOCATION_UNHANDLED FALSE
diff --git a/ui/dbus.h b/ui/dbus.h
index 3e89eafcab..64c77cab44 100644
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -24,6 +24,7 @@
 #ifndef UI_DBUS_H_
 #define UI_DBUS_H_
 
+#include "chardev/char-socket.h"
 #include "qemu/dbus.h"
 #include "qom/object.h"
 #include "ui/console.h"
@@ -56,11 +57,15 @@ struct DBusDisplay {
 QemuDBusDisplay1Clipboard *clipboard;
 QemuDBusDisplay1Clipboard *clipboard_proxy;
 DBusClipboardRequest clipboard_request[QEMU_CLIPBOARD_SELECTION__COUNT];
+
+Notifier notifier;
 };
 
 #define TYPE_DBUS_DISPLAY "dbus-display"
 OBJECT_DECLARE_SIMPLE_TYPE(DBusDisplay, DBUS_DISPLAY)
 
+void dbus_display_notifier_add(Notifier *notifier);
+
 #define DBUS_DISPLAY_TYPE_CONSOLE dbus_display_console_get_type()
 G_DECLARE_FINAL_TYPE(DBusDisplayConsole,
  dbus_display_console,
@@ -95,6 +100,45 @@ dbus_display_listener_get_bus_name(DBusDisplayListener 
*ddl);
 extern const DisplayChangeListenerOps dbus_gl_dcl_ops;
 extern const DisplayChangeListenerOps dbus_dcl_ops;
 
+#define TYPE_CHARDEV_DBUS "chardev-dbus"
+
+typedef struct DBusChardevClass {
+SocketChardevClass parent_class;
+
+void (*parent_chr_be_event)(Chardev *s, QEMUChrEvent event);
+} DBusChardevClass;
+
+DECLARE_CLASS_CHECKERS(DBusChardevClass, DBUS_CHARDEV,
+   TYPE_CHARDEV_DBUS)
+
+typedef struct DBusChardev {
+SocketChardev parent;
+
+bool exported;
+QemuDBusDisplay1Chardev *iface;
+} DBusChardev;
+
+DECLARE_INSTANCE_CHECKER(DBusChardev, DBUS_CHARDEV, TYPE_CHARDEV_DBUS)
+
+#define CHARDEV_IS_DBUS(chr) \
+object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_DBUS)
+
+typedef enum {
+DBUS_DISPLAY_CHARDEV_OPEN,
+DBUS_DISPLAY_CHARDEV_CLOSE,
+} DBusDisplayEventType;
+
+typedef struct DBusDisplayEvent {
+DBusDisplayEventType type;
+union {
+

[PATCH v2 34/37] option: add g_auto for QemuOpts

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Used in the next commit.

Signed-off-by: Marc-André Lureau 
---
 include/qemu/option.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/qemu/option.h b/include/qemu/option.h
index 306bf07575..bbd86e1c4e 100644
--- a/include/qemu/option.h
+++ b/include/qemu/option.h
@@ -150,4 +150,6 @@ QDict *keyval_parse(const char *params, const char 
*implied_key,
 bool *help, Error **errp);
 void keyval_merge(QDict *old, const QDict *new, Error **errp);
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuOpts, qemu_opts_del)
+
 #endif
-- 
2.33.0.721.g106298f7f9




[PATCH v2 33/37] chardev: make socket derivable

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 include/chardev/char-socket.h | 84 +++
 chardev/char-socket.c | 58 +---
 2 files changed, 85 insertions(+), 57 deletions(-)
 create mode 100644 include/chardev/char-socket.h

diff --git a/include/chardev/char-socket.h b/include/chardev/char-socket.h
new file mode 100644
index 00..1a9274f2e3
--- /dev/null
+++ b/include/chardev/char-socket.h
@@ -0,0 +1,84 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef CHAR_SOCKET_H_
+#define CHAR_SOCKET_H_
+
+#include "io/channel-socket.h"
+#include "io/channel-tls.h"
+#include "io/net-listener.h"
+#include "chardev/char.h"
+#include "qom/object.h"
+
+#define TCP_MAX_FDS 16
+
+typedef struct {
+char buf[21];
+size_t buflen;
+} TCPChardevTelnetInit;
+
+typedef enum {
+TCP_CHARDEV_STATE_DISCONNECTED,
+TCP_CHARDEV_STATE_CONNECTING,
+TCP_CHARDEV_STATE_CONNECTED,
+} TCPChardevState;
+
+struct SocketChardev {
+Chardev parent;
+QIOChannel *ioc; /* Client I/O channel */
+QIOChannelSocket *sioc; /* Client master channel */
+QIONetListener *listener;
+GSource *hup_source;
+QCryptoTLSCreds *tls_creds;
+char *tls_authz;
+TCPChardevState state;
+int max_size;
+int do_telnetopt;
+int do_nodelay;
+int *read_msgfds;
+size_t read_msgfds_num;
+int *write_msgfds;
+size_t write_msgfds_num;
+bool registered_yank;
+
+SocketAddress *addr;
+bool is_listen;
+bool is_telnet;
+bool is_tn3270;
+GSource *telnet_source;
+TCPChardevTelnetInit *telnet_init;
+
+bool is_websock;
+
+GSource *reconnect_timer;
+int64_t reconnect_time;
+bool connect_err_reported;
+
+QIOTask *connect_task;
+};
+typedef struct SocketChardev SocketChardev;
+
+DECLARE_INSTANCE_CHECKER(SocketChardev, SOCKET_CHARDEV,
+ TYPE_CHARDEV_SOCKET)
+
+#endif /* CHAR_SOCKET_H_ */
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index a2b02e021d..d619088232 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -25,9 +25,7 @@
 #include "qemu/osdep.h"
 #include "chardev/char.h"
 #include "io/channel-socket.h"
-#include "io/channel-tls.h"
 #include "io/channel-websock.h"
-#include "io/net-listener.h"
 #include "qemu/error-report.h"
 #include "qemu/module.h"
 #include "qemu/option.h"
@@ -37,61 +35,7 @@
 #include "qemu/yank.h"
 
 #include "chardev/char-io.h"
-#include "qom/object.h"
-
-/***/
-/* TCP Net console */
-
-#define TCP_MAX_FDS 16
-
-typedef struct {
-char buf[21];
-size_t buflen;
-} TCPChardevTelnetInit;
-
-typedef enum {
-TCP_CHARDEV_STATE_DISCONNECTED,
-TCP_CHARDEV_STATE_CONNECTING,
-TCP_CHARDEV_STATE_CONNECTED,
-} TCPChardevState;
-
-struct SocketChardev {
-Chardev parent;
-QIOChannel *ioc; /* Client I/O channel */
-QIOChannelSocket *sioc; /* Client master channel */
-QIONetListener *listener;
-GSource *hup_source;
-QCryptoTLSCreds *tls_creds;
-char *tls_authz;
-TCPChardevState state;
-int max_size;
-int do_telnetopt;
-int do_nodelay;
-int *read_msgfds;
-size_t read_msgfds_num;
-int *write_msgfds;
-size_t write_msgfds_num;
-bool registered_yank;
-
-SocketAddress *addr;
-bool is_listen;
-bool is_telnet;
-bool is_tn3270;
-GSource *telnet_source;
-TCPChardevTelnetInit *telnet_init;
-
-bool is_websock;
-
-GSource *reconnect_timer;
-int64_t reconnect_time;
-bool connect_err_reported;
-
-QIOTask *connect_task;
-};
-typedef struct SocketChardev SocketChardev;
-
-DECLARE_INSTANCE_CHECKER(SocketChardev, SOCKET_CHARDEV,
- TYPE_CHARDEV_SOCKET)
+#include "chardev/char-socket.h"
 
 static gboolean 

[PATCH v2 29/37] tests: start dbus-display-test

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Cover basic display interface usage. More cases to be added to cover
disconnections, multiple connections, corner cases. At this point, they
would be better written in Rust or Python though.

The proxy also covers reading the properties, since they are
automatically loaded at creation.

Signed-off-by: Marc-André Lureau 
---
 tests/qtest/dbus-display-test.c | 281 
 tests/qtest/meson.build |   8 +
 2 files changed, 289 insertions(+)
 create mode 100644 tests/qtest/dbus-display-test.c

diff --git a/tests/qtest/dbus-display-test.c b/tests/qtest/dbus-display-test.c
new file mode 100644
index 00..84278d2da6
--- /dev/null
+++ b/tests/qtest/dbus-display-test.c
@@ -0,0 +1,281 @@
+#include "qemu/osdep.h"
+#include "qemu/dbus.h"
+#include 
+#include 
+#include "libqos/libqtest.h"
+#include "qemu-common.h"
+#include "dbus-display1.h"
+
+static GDBusConnection*
+test_dbus_p2p_from_fd(int fd)
+{
+g_autoptr(GError) err = NULL;
+g_autoptr(GSocket) socket = NULL;
+g_autoptr(GSocketConnection) socketc = NULL;
+GDBusConnection *conn;
+
+socket = g_socket_new_from_fd(fd, );
+g_assert_no_error(err);
+
+socketc = g_socket_connection_factory_create_connection(socket);
+g_assert(socketc != NULL);
+
+conn = g_dbus_connection_new_sync(
+G_IO_STREAM(socketc), NULL,
+G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
+NULL, NULL, );
+g_assert_no_error(err);
+
+return conn;
+}
+
+static void
+test_setup(QTestState **qts, GDBusConnection **conn)
+{
+int pair[2];
+
+*qts = qtest_init("-display dbus,p2p=yes -name dbus-test");
+
+g_assert_cmpint(socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0);
+
+qtest_qmp_add_client(*qts, "@dbus-display", pair[1]);
+
+*conn = test_dbus_p2p_from_fd(pair[0]);
+g_dbus_connection_start_message_processing(*conn);
+}
+
+static void
+test_dbus_display_vm(void)
+{
+g_autoptr(GError) err = NULL;
+g_autoptr(GDBusConnection) conn = NULL;
+g_autoptr(QemuDBusDisplay1VMProxy) vm = NULL;
+QTestState *qts = NULL;
+
+test_setup(, );
+
+vm = QEMU_DBUS_DISPLAY1_VM_PROXY(
+qemu_dbus_display1_vm_proxy_new_sync(
+conn,
+G_DBUS_PROXY_FLAGS_NONE,
+NULL,
+DBUS_DISPLAY1_ROOT "/VM",
+NULL,
+));
+g_assert_no_error(err);
+
+g_assert_cmpstr(
+qemu_dbus_display1_vm_get_name(QEMU_DBUS_DISPLAY1_VM(vm)),
+==,
+"dbus-test");
+qtest_quit(qts);
+}
+
+typedef struct TestDBusConsoleRegister {
+GMainLoop *loop;
+GThread *thread;
+GDBusConnection *listener_conn;
+GDBusObjectManagerServer *server;
+} TestDBusConsoleRegister;
+
+static gboolean listener_handle_scanout(
+QemuDBusDisplay1Listener *object,
+GDBusMethodInvocation *invocation,
+guint arg_width,
+guint arg_height,
+guint arg_stride,
+guint arg_pixman_format,
+GVariant *arg_data,
+TestDBusConsoleRegister *test)
+{
+g_main_loop_quit(test->loop);
+
+return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static void
+test_dbus_console_setup_listener(TestDBusConsoleRegister *test)
+{
+g_autoptr(GDBusObjectSkeleton) listener = NULL;
+g_autoptr(QemuDBusDisplay1ListenerSkeleton) iface = NULL;
+
+test->server = g_dbus_object_manager_server_new(DBUS_DISPLAY1_ROOT);
+listener = g_dbus_object_skeleton_new(DBUS_DISPLAY1_ROOT "/Listener");
+iface = QEMU_DBUS_DISPLAY1_LISTENER_SKELETON(
+qemu_dbus_display1_listener_skeleton_new());
+g_object_connect(iface,
+ "signal::handle-scanout", listener_handle_scanout, test,
+ NULL);
+g_dbus_object_skeleton_add_interface(listener,
+ G_DBUS_INTERFACE_SKELETON(iface));
+g_dbus_object_manager_server_export(test->server, listener);
+g_dbus_object_manager_server_set_connection(test->server,
+test->listener_conn);
+
+g_dbus_connection_start_message_processing(test->listener_conn);
+}
+
+static void
+test_dbus_console_registered(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+TestDBusConsoleRegister *test = user_data;
+g_autoptr(GError) err = NULL;
+
+qemu_dbus_display1_console_call_register_listener_finish(
+QEMU_DBUS_DISPLAY1_CONSOLE(source_object),
+NULL, res, );
+g_assert_no_error(err);
+
+test->listener_conn = g_thread_join(test->thread);
+test_dbus_console_setup_listener(test);
+}
+
+static gpointer
+test_dbus_p2p_server_setup_thread(gpointer data)
+{
+return test_dbus_p2p_from_fd(GPOINTER_TO_INT(data));
+}
+
+static void
+test_dbus_display_console(void)
+{
+g_autoptr(GError) err = NULL;
+g_autoptr(GDBusConnection) conn = NULL;
+

[PATCH v2 31/37] ui/dbus: add clipboard interface

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Expose the clipboard API over D-Bus. See the interface documentation for
further details.

Signed-off-by: Marc-André Lureau 
---
 ui/dbus.h|  14 ++
 ui/dbus-clipboard.c  | 457 +++
 ui/dbus.c|   7 +
 ui/dbus-display1.xml |  97 +
 ui/meson.build   |   1 +
 ui/trace-events  |   3 +
 6 files changed, 579 insertions(+)
 create mode 100644 ui/dbus-clipboard.c

diff --git a/ui/dbus.h b/ui/dbus.h
index ca1f0f4ab9..3e89eafcab 100644
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -27,9 +27,16 @@
 #include "qemu/dbus.h"
 #include "qom/object.h"
 #include "ui/console.h"
+#include "ui/clipboard.h"
 
 #include "dbus-display1.h"
 
+typedef struct DBusClipboardRequest {
+GDBusMethodInvocation *invocation;
+QemuClipboardType type;
+guint timeout_id;
+} DBusClipboardRequest;
+
 struct DBusDisplay {
 Object parent;
 
@@ -44,6 +51,11 @@ struct DBusDisplay {
 QemuDBusDisplay1VM *iface;
 GPtrArray *consoles;
 GCancellable *add_client_cancellable;
+
+QemuClipboardPeer clipboard_peer;
+QemuDBusDisplay1Clipboard *clipboard;
+QemuDBusDisplay1Clipboard *clipboard_proxy;
+DBusClipboardRequest clipboard_request[QEMU_CLIPBOARD_SELECTION__COUNT];
 };
 
 #define TYPE_DBUS_DISPLAY "dbus-display"
@@ -83,4 +95,6 @@ dbus_display_listener_get_bus_name(DBusDisplayListener *ddl);
 extern const DisplayChangeListenerOps dbus_gl_dcl_ops;
 extern const DisplayChangeListenerOps dbus_dcl_ops;
 
+void dbus_clipboard_init(DBusDisplay *dpy);
+
 #endif /* UI_DBUS_H_ */
diff --git a/ui/dbus-clipboard.c b/ui/dbus-clipboard.c
new file mode 100644
index 00..5843d26cd2
--- /dev/null
+++ b/ui/dbus-clipboard.c
@@ -0,0 +1,457 @@
+/*
+ * QEMU DBus display
+ *
+ * Copyright (c) 2021 Marc-André Lureau 
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "qemu/dbus.h"
+#include "qemu/main-loop.h"
+#include "qom/object_interfaces.h"
+#include "sysemu/sysemu.h"
+#include "qapi/error.h"
+#include "trace.h"
+
+#include "dbus.h"
+
+#define MIME_TEXT_PLAIN_UTF8 "text/plain;charset=utf-8"
+
+static void
+dbus_clipboard_complete_request(
+DBusDisplay *dpy,
+GDBusMethodInvocation *invocation,
+QemuClipboardInfo *info,
+QemuClipboardType type)
+{
+GVariant *v_data = g_variant_new_from_data(
+G_VARIANT_TYPE("ay"),
+info->types[type].data,
+info->types[type].size,
+TRUE,
+(GDestroyNotify)qemu_clipboard_info_unref,
+qemu_clipboard_info_ref(info));
+
+qemu_dbus_display1_clipboard_complete_request(
+dpy->clipboard, invocation,
+MIME_TEXT_PLAIN_UTF8, v_data);
+}
+
+static void
+dbus_clipboard_update_info(DBusDisplay *dpy, QemuClipboardInfo *info)
+{
+bool self_update = info->owner == >clipboard_peer;
+const char *mime[QEMU_CLIPBOARD_TYPE__COUNT + 1] = { 0, };
+DBusClipboardRequest *req;
+int i = 0;
+
+if (info->owner == NULL) {
+if (dpy->clipboard_proxy) {
+qemu_dbus_display1_clipboard_call_release(
+dpy->clipboard_proxy,
+info->selection,
+G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+}
+return;
+}
+
+if (self_update || !info->has_serial) {
+return;
+}
+
+req = >clipboard_request[info->selection];
+if (req->invocation && info->types[req->type].data) {
+dbus_clipboard_complete_request(dpy, req->invocation, info, req->type);
+g_clear_object(>invocation);
+g_source_remove(req->timeout_id);
+req->timeout_id = 0;
+return;
+}
+
+if (info->types[QEMU_CLIPBOARD_TYPE_TEXT].available) {
+mime[i++] = MIME_TEXT_PLAIN_UTF8;
+}
+
+if (i > 0) {
+if (dpy->clipboard_proxy) {
+qemu_dbus_display1_clipboard_call_grab(
+dpy->clipboard_proxy,
+info->selection,
+

[PATCH v2 28/37] tests/qtests: add qtest_qmp_add_client()

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 tests/qtest/libqos/libqtest.h | 10 ++
 tests/qtest/libqtest.c| 19 +++
 2 files changed, 29 insertions(+)

diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h
index a68dcd79d4..9e5f9118f3 100644
--- a/tests/qtest/libqos/libqtest.h
+++ b/tests/qtest/libqos/libqtest.h
@@ -728,6 +728,16 @@ void qtest_qmp_device_add_qdict(QTestState *qts, const 
char *drv,
 void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id,
   const char *fmt, ...) GCC_FMT_ATTR(4, 5);
 
+/**
+ * qtest_qmp_add_client:
+ * @qts: QTestState instance to operate on
+ * @protocol: the protocol to add to
+ * @fd: the client file-descriptor
+ *
+ * Call QMP `getfd` followed by `add_client` with the given @fd.
+ */
+void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd);
+
 /**
  * qtest_qmp_device_del:
  * @qts: QTestState instance to operate on
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 73f6b977a6..c8ea5499a0 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -1367,6 +1367,25 @@ void qtest_qmp_device_add(QTestState *qts, const char 
*driver, const char *id,
 qobject_unref(args);
 }
 
+void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd)
+{
+QDict *resp;
+
+resp = qtest_qmp_fds(qts, , 1, "{'execute': 'getfd',"
+ "'arguments': {'fdname': 'fdname'}}");
+g_assert(resp);
+g_assert(!qdict_haskey(resp, "event")); /* We don't expect any events */
+g_assert(!qdict_haskey(resp, "error"));
+qobject_unref(resp);
+
+resp = qtest_qmp(
+qts, "{'execute': 'add_client',"
+"'arguments': {'protocol': %s, 'fdname': 'fdname'}}", protocol);
+g_assert(resp);
+g_assert(!qdict_haskey(resp, "event")); /* We don't expect any events */
+g_assert(!qdict_haskey(resp, "error"));
+qobject_unref(resp);
+}
 
 /*
  * Generic hot-unplugging test via the device_del QMP command.
-- 
2.33.0.721.g106298f7f9




[PATCH v2 32/37] chardev: teach socket to accept no addresses

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

The following patches are going to use CharSocket as a base class for
sockets that are created with a given fd (without a given address).

Signed-off-by: Marc-André Lureau 
---
 chardev/char-socket.c | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 836cfa0bc2..a2b02e021d 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -1248,6 +1248,10 @@ static int qmp_chardev_open_socket_server(Chardev *chr,
 qio_net_listener_set_name(s->listener, name);
 g_free(name);
 
+if (s->addr->type == SOCKET_ADDRESS_TYPE_FD && !*s->addr->u.fd.str) {
+goto skip_listen;
+}
+
 if (qio_net_listener_open_sync(s->listener, s->addr, 1, errp) < 0) {
 object_unref(OBJECT(s->listener));
 s->listener = NULL;
@@ -1256,6 +1260,8 @@ static int qmp_chardev_open_socket_server(Chardev *chr,
 
 qapi_free_SocketAddress(s->addr);
 s->addr = socket_local_address(s->listener->sioc[0]->fd, errp);
+
+skip_listen:
 update_disconnected_filename(s);
 
 if (is_waitconnect) {
@@ -1466,9 +1472,9 @@ static void qemu_chr_parse_socket(QemuOpts *opts, 
ChardevBackend *backend,
 SocketAddressLegacy *addr;
 ChardevSocket *sock;
 
-if ((!!path + !!fd + !!host) != 1) {
+if ((!!path + !!fd + !!host) > 1) {
 error_setg(errp,
-   "Exactly one of 'path', 'fd' or 'host' required");
+   "None or one of 'path', 'fd' or 'host' option required.");
 return;
 }
 
@@ -1542,12 +1548,10 @@ static void qemu_chr_parse_socket(QemuOpts *opts, 
ChardevBackend *backend,
 .has_ipv6 = qemu_opt_get(opts, "ipv6"),
 .ipv6 = qemu_opt_get_bool(opts, "ipv6", 0),
 };
-} else if (fd) {
+} else {
 addr->type = SOCKET_ADDRESS_TYPE_FD;
 addr->u.fd.data = g_new(String, 1);
 addr->u.fd.data->str = g_strdup(fd);
-} else {
-g_assert_not_reached();
 }
 sock->addr = addr;
 }
-- 
2.33.0.721.g106298f7f9




[PATCH v2 26/37] ui: add a D-Bus display backend

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

The "dbus" display backend exports the QEMU consoles and other
UI-related interfaces over D-Bus.

By default, the connection is established on the session bus, but you
can specify a different bus with the "addr" option.

The backend takes the "org.qemu" service name, while still allowing
further instances to queue on the same name (so you can lookup all the
available instances too). It accepts any number of clients at this
point, although this is expected to evolve with options to restrict
clients, or only accept p2p via fd passing.

The interface is intentionally very close to the internal QEMU API,
and can be introspected or interacted with busctl/dfeet etc:

$ ./qemu-system-x86_64 -name MyVM -display dbus
$ busctl --user introspect org.qemu /org/qemu/Display1/Console_0

org.qemu.Display1.Console   interface - -   -
.RegisterListener   methodh -   -
.SetUIInfo  methodqqiiuu-   -
.DeviceAddress  property  s "pci//01.0" 
emits-change
.Head   property  u 0   
emits-change
.Height property  u 480 
emits-change
.Label  property  s "VGA"   
emits-change
.Type   property  s "Graphic"   
emits-change
.Width  property  u 640 
emits-change
[...]

See the interfaces XML source file and Sphinx docs for the generated API
documentations.

Signed-off-by: Marc-André Lureau 
---
 meson.build  |  12 +-
 qapi/ui.json |  27 ++-
 include/qemu/dbus.h  |  19 ++
 ui/dbus.h|  83 
 ui/dbus-console.c| 497 +++
 ui/dbus-error.c  |  48 +
 ui/dbus-listener.c   | 486 ++
 ui/dbus.c| 262 +++
 meson_options.txt|   2 +
 qemu-options.hx  |  15 ++
 ui/dbus-display1.xml | 378 
 ui/meson.build   |  22 ++
 ui/trace-events  |  11 +
 13 files changed, 1859 insertions(+), 3 deletions(-)
 create mode 100644 ui/dbus.h
 create mode 100644 ui/dbus-console.c
 create mode 100644 ui/dbus-error.c
 create mode 100644 ui/dbus-listener.c
 create mode 100644 ui/dbus.c

diff --git a/meson.build b/meson.build
index 9494590aa2..b571fde310 100644
--- a/meson.build
+++ b/meson.build
@@ -1198,6 +1198,15 @@ endif
 have_host_block_device = (targetos != 'darwin' or
 cc.has_header('IOKit/storage/IOMedia.h'))
 
+dbus_display = false
+if not get_option('dbus_display').disabled()
+  # FIXME enable_modules shouldn't be necessary, but: 
https://github.com/mesonbuild/meson/issues/8333
+  dbus_display = gio.version().version_compare('>=2.64') and 
config_host.has_key('GDBUS_CODEGEN') and enable_modules
+  if get_option('dbus_display').enabled() and not dbus_display
+error('Requirements missing to enable -display dbus')
+  endif
+endif
+
 #
 # config-host.h #
 #
@@ -1299,7 +1308,7 @@ config_host_data.set('CONFIG_SPICE_PROTOCOL_MINOR', 
spice_protocol.version().spl
 config_host_data.set('CONFIG_SPICE_PROTOCOL_MICRO', 
spice_protocol.version().split('.')[2])
 endif
 config_host_data.set('CONFIG_SPICE', spice.found())
-config_host_data.set('CONFIG_X11', x11.found())
+config_host_data.set('CONFIG_DBUS_DISPLAY', dbus_display)
 config_host_data.set('CONFIG_CFI', get_option('cfi'))
 config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
 config_host_data.set('QEMU_VERSION_MAJOR', 
meson.project_version().split('.')[0])
@@ -2892,6 +2901,7 @@ summary_info += {'fuzzing support':   
config_host.has_key('CONFIG_FUZZ')}
 if have_system
   summary_info += {'Audio drivers': config_host['CONFIG_AUDIO_DRIVERS']}
 endif
+summary_info += {'D-Bus display': dbus_display}
 summary_info += {'Trace backends':config_host['TRACE_BACKENDS']}
 if config_host['TRACE_BACKENDS'].split().contains('simple')
   summary_info += {'Trace output file': config_host['CONFIG_TRACE_FILE'] + 
'-'}
diff --git a/qapi/ui.json b/qapi/ui.json
index d7567ac866..5ca604bd90 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1121,6 +1121,23 @@
 { 'struct'  : 'DisplayEGLHeadless',
   'data': { '*rendernode' : 'str' } }
 
+##
+# @DisplayDBus:
+#
+# DBus display options.
+#
+# @addr: The D-Bus bus address (default to the session bus).
+#
+# @rendernode: Which DRM render node should be used. Default is the first
+#  available node on the host.
+#
+# Since: 6.2
+#
+##
+{ 'struct'  : 'DisplayDBus',
+  'data': { '*rendernode' : 'str',
+'*addr': 'str' } }
+
  ##
  # @DisplayGLMode:
  #
@@ -1186,6 +1203,8 @@
 # application to connect to it. The server will redirect
 # the serial console and QEMU monitors. 

[PATCH v2 27/37] ui/dbus: add p2p=on/off option

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Add an option to use direct connections instead of via the bus. Clients
are accepted via QMP add_client.

This allows to provide the D-Bus display without a bus. It also
simplifies the testing setup (some CI have issues to setup a D-Bus bus
in a container).

Signed-off-by: Marc-André Lureau 
---
 qapi/misc.json|   4 +-
 qapi/ui.json  |   6 ++-
 include/qemu/cutils.h |   5 ++
 include/ui/dbus-display.h |  17 +++
 include/ui/dbus-module.h  |  11 
 ui/dbus.h |   2 +
 monitor/qmp-cmds.c|  13 +
 ui/dbus-console.c |   2 +-
 ui/dbus-listener.c|   2 +-
 ui/dbus-module.c  |  35 +
 ui/dbus.c | 104 --
 qemu-options.hx   |   2 +
 ui/meson.build|   3 ++
 13 files changed, 196 insertions(+), 10 deletions(-)
 create mode 100644 include/ui/dbus-display.h
 create mode 100644 include/ui/dbus-module.h
 create mode 100644 ui/dbus-module.c

diff --git a/qapi/misc.json b/qapi/misc.json
index 5c2ca3b556..887bcf54bb 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -14,8 +14,8 @@
 # Allow client connections for VNC, Spice and socket based
 # character devices to be passed in to QEMU via SCM_RIGHTS.
 #
-# @protocol: protocol name. Valid names are "vnc", "spice" or the
-#name of a character device (eg. from -chardev id=)
+# @protocol: protocol name. Valid names are "vnc", "spice", "@dbus-display" or
+#the name of a character device (eg. from -chardev id=)
 #
 # @fdname: file descriptor name previously passed via 'getfd' command
 #
diff --git a/qapi/ui.json b/qapi/ui.json
index 5ca604bd90..f23d012cb8 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1131,12 +1131,16 @@
 # @rendernode: Which DRM render node should be used. Default is the first
 #  available node on the host.
 #
+# @p2p: Whether to use peer-to-peer connections (accepted through
+#   ``add_client``).
+#
 # Since: 6.2
 #
 ##
 { 'struct'  : 'DisplayDBus',
   'data': { '*rendernode' : 'str',
-'*addr': 'str' } }
+'*addr': 'str',
+'*p2p': 'bool' } }
 
  ##
  # @DisplayGLMode:
diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index 986ed8e15f..320543950c 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -209,4 +209,9 @@ int qemu_pstrcmp0(const char **str1, const char **str2);
  */
 char *get_relocated_path(const char *dir);
 
+static inline const char *yes_no(bool b)
+{
+ return b ? "yes" : "no";
+}
+
 #endif
diff --git a/include/ui/dbus-display.h b/include/ui/dbus-display.h
new file mode 100644
index 00..88f153c237
--- /dev/null
+++ b/include/ui/dbus-display.h
@@ -0,0 +1,17 @@
+#ifndef DBUS_DISPLAY_H_
+#define DBUS_DISPLAY_H_
+
+#include "qapi/error.h"
+#include "ui/dbus-module.h"
+
+static inline bool qemu_using_dbus_display(Error **errp)
+{
+if (!using_dbus_display) {
+error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE,
+  "D-Bus display is not in use");
+return false;
+}
+return true;
+}
+
+#endif /* DBUS_DISPLAY_H_ */
diff --git a/include/ui/dbus-module.h b/include/ui/dbus-module.h
new file mode 100644
index 00..ace4a17a5c
--- /dev/null
+++ b/include/ui/dbus-module.h
@@ -0,0 +1,11 @@
+#ifndef DBUS_MODULE_H_
+#define DBUS_MODULE_H_
+
+struct QemuDBusDisplayOps {
+bool (*add_client)(int csock, Error **errp);
+};
+
+extern int using_dbus_display;
+extern struct QemuDBusDisplayOps qemu_dbus_display;
+
+#endif /* DBUS_MODULE_H_*/
diff --git a/ui/dbus.h b/ui/dbus.h
index d3c9598dd1..4698d32463 100644
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -34,6 +34,7 @@ struct DBusDisplay {
 Object parent;
 
 DisplayGLMode gl_mode;
+bool p2p;
 char *dbus_addr;
 DisplayGLCtx glctx;
 
@@ -41,6 +42,7 @@ struct DBusDisplay {
 GDBusObjectManagerServer *server;
 QemuDBusDisplay1VM *iface;
 GPtrArray *consoles;
+GCancellable *add_client_cancellable;
 };
 
 #define TYPE_DBUS_DISPLAY "dbus-display"
diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c
index 5c0d5e116b..aa6b012313 100644
--- a/monitor/qmp-cmds.c
+++ b/monitor/qmp-cmds.c
@@ -24,6 +24,7 @@
 #include "chardev/char.h"
 #include "ui/qemu-spice.h"
 #include "ui/console.h"
+#include "ui/dbus-display.h"
 #include "sysemu/kvm.h"
 #include "sysemu/runstate.h"
 #include "sysemu/runstate-action.h"
@@ -281,6 +282,18 @@ void qmp_add_client(const char *protocol, const char 
*fdname,
 skipauth = has_skipauth ? skipauth : false;
 vnc_display_add_client(NULL, fd, skipauth);
 return;
+#endif
+#ifdef CONFIG_DBUS_DISPLAY
+} else if (strcmp(protocol, "@dbus-display") == 0) {
+if (!qemu_using_dbus_display(errp)) {
+close(fd);
+return;
+}
+if (!qemu_dbus_display.add_client(fd, errp)) {
+close(fd);
+return;
+}
+return;
 #endif
 } 

[PATCH v2 25/37] build-sys: set glib dependency version

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Further meson configuration tests are to be added based on the glib
version. Also correct the version reporting in the config log.

Signed-off-by: Marc-André Lureau 
---
 configure   | 1 +
 meson.build | 6 --
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/configure b/configure
index 375cde2b44..57e363fd73 100755
--- a/configure
+++ b/configure
@@ -4889,6 +4889,7 @@ echo "QEMU_CFLAGS=$QEMU_CFLAGS" >> $config_host_mak
 echo "QEMU_CXXFLAGS=$QEMU_CXXFLAGS" >> $config_host_mak
 echo "GLIB_CFLAGS=$glib_cflags" >> $config_host_mak
 echo "GLIB_LIBS=$glib_libs" >> $config_host_mak
+echo "GLIB_VERSION=$(pkg-config --modversion glib-2.0)" >> $config_host_mak
 echo "QEMU_LDFLAGS=$QEMU_LDFLAGS" >> $config_host_mak
 echo "LD_I386_EMULATION=$ld_i386_emulation" >> $config_host_mak
 echo "EXESUF=$EXESUF" >> $config_host_mak
diff --git a/meson.build b/meson.build
index e1cddf5139..9494590aa2 100644
--- a/meson.build
+++ b/meson.build
@@ -311,14 +311,16 @@ endif
 add_project_arguments(config_host['GLIB_CFLAGS'].split(),
   native: false, language: ['c', 'cpp', 'objc'])
 glib = declare_dependency(compile_args: config_host['GLIB_CFLAGS'].split(),
-  link_args: config_host['GLIB_LIBS'].split())
+  link_args: config_host['GLIB_LIBS'].split(),
+  version: config_host['GLIB_VERSION'])
 # override glib dep with the configure results (for subprojects)
 meson.override_dependency('glib-2.0', glib)
 
 gio = not_found
 if 'CONFIG_GIO' in config_host
   gio = declare_dependency(compile_args: config_host['GIO_CFLAGS'].split(),
-   link_args: config_host['GIO_LIBS'].split())
+   link_args: config_host['GIO_LIBS'].split(),
+   version: config_host['GLIB_VERSION'])
 endif
 lttng = not_found
 if 'CONFIG_TRACE_UST' in config_host
-- 
2.33.0.721.g106298f7f9




[PATCH v2 30/37] audio: add "dbus" audio backend

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Add a new -audio backend that accepts D-Bus clients/listeners to handle
playback & recording, to be exported via the -display dbus.

Example usage:
-audiodev dbus,in.mixing-engine=off,out.mixing-engine=off,id=dbus
-display dbus,audiodev=dbus

Signed-off-by: Marc-André Lureau 
---
 qapi/audio.json|   3 +-
 qapi/ui.json   |   5 +-
 audio/audio_int.h  |   7 +
 audio/audio_template.h |   2 +
 ui/dbus.h  |   1 +
 audio/audio.c  |   1 +
 audio/dbusaudio.c  | 654 +
 ui/dbus.c  |  35 +++
 audio/meson.build  |   8 +-
 audio/trace-events |   5 +
 qemu-options.hx|   3 +
 ui/dbus-display1.xml   | 211 +
 12 files changed, 932 insertions(+), 3 deletions(-)
 create mode 100644 audio/dbusaudio.c

diff --git a/qapi/audio.json b/qapi/audio.json
index 9cba0df8a4..693e327c6b 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -386,7 +386,7 @@
 # Since: 4.0
 ##
 { 'enum': 'AudiodevDriver',
-  'data': [ 'none', 'alsa', 'coreaudio', 'dsound', 'jack', 'oss', 'pa',
+  'data': [ 'none', 'alsa', 'coreaudio', 'dbus', 'dsound', 'jack', 'oss', 'pa',
 'sdl', 'spice', 'wav' ] }
 
 ##
@@ -412,6 +412,7 @@
 'none':  'AudiodevGenericOptions',
 'alsa':  'AudiodevAlsaOptions',
 'coreaudio': 'AudiodevCoreaudioOptions',
+'dbus':  'AudiodevGenericOptions',
 'dsound':'AudiodevDsoundOptions',
 'jack':  'AudiodevJackOptions',
 'oss':   'AudiodevOssOptions',
diff --git a/qapi/ui.json b/qapi/ui.json
index f23d012cb8..b9262ae1d9 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -1134,13 +1134,16 @@
 # @p2p: Whether to use peer-to-peer connections (accepted through
 #   ``add_client``).
 #
+# @audiodev: Use the specified DBus audiodev to export audio.
+#
 # Since: 6.2
 #
 ##
 { 'struct'  : 'DisplayDBus',
   'data': { '*rendernode' : 'str',
 '*addr': 'str',
-'*p2p': 'bool' } }
+'*p2p': 'bool',
+'*audiodev': 'str' } }
 
  ##
  # @DisplayGLMode:
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 6d685e24a3..428a091d05 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -31,6 +31,10 @@
 #endif
 #include "mixeng.h"
 
+#ifdef CONFIG_GIO
+#include 
+#endif
+
 struct audio_pcm_ops;
 
 struct audio_callback {
@@ -140,6 +144,9 @@ struct audio_driver {
 const char *descr;
 void *(*init) (Audiodev *);
 void (*fini) (void *);
+#ifdef CONFIG_GIO
+void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager);
+#endif
 struct audio_pcm_ops *pcm_ops;
 int can_be_default;
 int max_voices_out;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index c6714946aa..d2d348638b 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -327,6 +327,8 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, 
TYPE)(Audiodev *dev)
 case AUDIODEV_DRIVER_COREAUDIO:
 return qapi_AudiodevCoreaudioPerDirectionOptions_base(
 dev->u.coreaudio.TYPE);
+case AUDIODEV_DRIVER_DBUS:
+return dev->u.dbus.TYPE;
 case AUDIODEV_DRIVER_DSOUND:
 return dev->u.dsound.TYPE;
 case AUDIODEV_DRIVER_JACK:
diff --git a/ui/dbus.h b/ui/dbus.h
index 4698d32463..ca1f0f4ab9 100644
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -36,6 +36,7 @@ struct DBusDisplay {
 DisplayGLMode gl_mode;
 bool p2p;
 char *dbus_addr;
+char *audiodev;
 DisplayGLCtx glctx;
 
 GDBusConnection *bus;
diff --git a/audio/audio.c b/audio/audio.c
index 54a153c0ef..dc28685d22 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -2000,6 +2000,7 @@ void audio_create_pdos(Audiodev *dev)
 CASE(NONE, none, );
 CASE(ALSA, alsa, Alsa);
 CASE(COREAUDIO, coreaudio, Coreaudio);
+CASE(DBUS, dbus, );
 CASE(DSOUND, dsound, );
 CASE(JACK, jack, Jack);
 CASE(OSS, oss, Oss);
diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c
new file mode 100644
index 00..f178b47dee
--- /dev/null
+++ b/audio/dbusaudio.c
@@ -0,0 +1,654 @@
+/*
+ * QEMU DBus audio
+ *
+ * Copyright (c) 2021 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 

[PATCH v2 23/37] docs: move D-Bus VMState documentation to source XML

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Use the source XML document as single reference, importing its
documentation via the dbus-doc directive.

Signed-off-by: Marc-André Lureau 
---
 docs/interop/dbus-vmstate.rst | 52 ++-
 backends/dbus-vmstate1.xml| 42 +++-
 2 files changed, 49 insertions(+), 45 deletions(-)

diff --git a/docs/interop/dbus-vmstate.rst b/docs/interop/dbus-vmstate.rst
index 1d719c1c60..5fb3f279e2 100644
--- a/docs/interop/dbus-vmstate.rst
+++ b/docs/interop/dbus-vmstate.rst
@@ -2,9 +2,6 @@
 D-Bus VMState
 =
 
-Introduction
-
-
 The QEMU dbus-vmstate object's aim is to migrate helpers' data running
 on a QEMU D-Bus bus. (refer to the :doc:`dbus` document for
 some recommendations on D-Bus usage)
@@ -26,49 +23,16 @@ dbus-vmstate object can be configured with the expected 
list of
 helpers by setting its ``id-list`` property, with a comma-separated
 ``Id`` list.
 
-Interface
-=
-
-On object path ``/org/qemu/VMState1``, the following
-``org.qemu.VMState1`` interface should be implemented:
-
-.. code:: xml
-
-  
-
-
-  
-
-
-  
-
-  
-
-"Id" property
--
-
-A string that identifies the helper uniquely. (maximum 256 bytes
-including terminating NUL byte)
-
-.. note::
-
-   The helper ID namespace is a separate namespace. In particular, it is not
-   related to QEMU "id" used in -object/-device objects.
-
-Load(in u8[] bytes) method
---
-
-The method called on destination with the state to restore.
+.. only:: sphinx4
 
-The helper may be initially started in a waiting state (with
-an --incoming argument for example), and it may resume on success.
+   .. dbus-doc:: backends/dbus-vmstate1.xml
 
-An error may be returned to the caller.
+.. only:: not sphinx4
 
-Save(out u8[] bytes) method

+   .. warning::
+  Sphinx 4 is required to build D-Bus documentation.
 
-The method called on the source to get the current state to be
-migrated. The helper should continue to run normally.
+  This is the content of ``backends/dbus-vmstate1.xml``:
 
-An error may be returned to the caller.
+   .. literalinclude:: ../../backends/dbus-vmstate1.xml
+  :language: xml
diff --git a/backends/dbus-vmstate1.xml b/backends/dbus-vmstate1.xml
index cc8563be4c..601ee8dc7e 100644
--- a/backends/dbus-vmstate1.xml
+++ b/backends/dbus-vmstate1.xml
@@ -1,10 +1,50 @@
-
+
 http://www.freedesktop.org/dbus/1.0/doc.dtd;>
+  
   
+
+
 
+
+
 
   
 
+
+
 
   
 
-- 
2.33.0.721.g106298f7f9




[PATCH v2 24/37] docs: add dbus-display documentation

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Wire up the dbus-display documentation. The interface and feature is
implemented next.

Signed-off-by: Marc-André Lureau 
---
 docs/interop/dbus-display.rst | 31 +++
 docs/interop/dbus.rst |  2 ++
 docs/interop/index.rst|  1 +
 ui/dbus-display1.xml  |  0
 4 files changed, 34 insertions(+)
 create mode 100644 docs/interop/dbus-display.rst
 create mode 100644 ui/dbus-display1.xml

diff --git a/docs/interop/dbus-display.rst b/docs/interop/dbus-display.rst
new file mode 100644
index 00..8c6e8e0f5a
--- /dev/null
+++ b/docs/interop/dbus-display.rst
@@ -0,0 +1,31 @@
+D-Bus display
+=
+
+QEMU can export the VM display through D-Bus (when started with ``-display
+dbus``), to allow out-of-process UIs, remote protocol servers or other
+interactive display usages.
+
+Various specialized D-Bus interfaces are available on different object paths
+under ``/org/qemu/Display1/``, depending on the VM configuration.
+
+QEMU also implements the standard interfaces, such as
+`org.freedesktop.DBus.Introspectable
+`_.
+
+.. contents::
+   :local:
+   :depth: 1
+
+.. only:: sphinx4
+
+   .. dbus-doc:: ui/dbus-display1.xml
+
+.. only:: not sphinx4
+
+   .. warning::
+  Sphinx 4 is required to build D-Bus documentation.
+
+  This is the content of ``ui/dbus-display1.xml``:
+
+   .. literalinclude:: ../../ui/dbus-display1.xml
+  :language: xml
diff --git a/docs/interop/dbus.rst b/docs/interop/dbus.rst
index be596d3f41..427debc9c5 100644
--- a/docs/interop/dbus.rst
+++ b/docs/interop/dbus.rst
@@ -108,3 +108,5 @@ QEMU Interfaces
 ===
 
 :doc:`dbus-vmstate`
+
+:doc:`dbus-display`
diff --git a/docs/interop/index.rst b/docs/interop/index.rst
index 47b9ed82bb..c59bac9834 100644
--- a/docs/interop/index.rst
+++ b/docs/interop/index.rst
@@ -12,6 +12,7 @@ are useful for making QEMU interoperate with other software.
bitmaps
dbus
dbus-vmstate
+   dbus-display
live-block-operations
pr-helper
qemu-ga
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
new file mode 100644
index 00..e69de29bb2
-- 
2.33.0.721.g106298f7f9




[PATCH v2 14/37] ui: add a gl-unblock warning timer

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Similar to the one that exists for Spice, so we can investigate if
something is locked.

Signed-off-by: Marc-André Lureau 
---
 ui/console.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/ui/console.c b/ui/console.c
index 8d641b9530..c62a33b1ec 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -129,6 +129,7 @@ struct QemuConsole {
 int dcls;
 DisplayChangeListener *gl;
 int gl_block;
+QEMUTimer *gl_unblock_timer;
 int window_id;
 
 /* Graphic console state.  */
@@ -284,8 +285,14 @@ void graphic_hw_update(QemuConsole *con)
 }
 }
 
+static void graphic_hw_gl_unblock_timer(void *opaque)
+{
+warn_report("console: no gl-unblock within one second");
+}
+
 void graphic_hw_gl_block(QemuConsole *con, bool block)
 {
+uint64_t timeout;
 assert(con != NULL);
 
 if (block) {
@@ -301,6 +308,14 @@ void graphic_hw_gl_block(QemuConsole *con, bool block)
 return;
 }
 con->hw_ops->gl_block(con->hw, block);
+
+if (block) {
+timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+timeout += 1000; /* one sec */
+timer_mod(con->gl_unblock_timer, timeout);
+} else {
+timer_del(con->gl_unblock_timer);
+}
 }
 
 void graphic_hw_gl_flushed(QemuConsole *con)
@@ -2024,6 +2039,8 @@ QemuConsole *graphic_console_init(DeviceState *dev, 
uint32_t head,
 
 surface = qemu_create_placeholder_surface(width, height, noinit);
 dpy_gfx_replace_surface(s, surface);
+s->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
+   graphic_hw_gl_unblock_timer, s);
 return s;
 }
 
-- 
2.33.0.721.g106298f7f9




[PATCH v2 18/37] ui: move qemu_spice_fill_device_address to ui/util.c

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Other backends can use it.

Signed-off-by: Marc-André Lureau 
---
 include/ui/console.h   |  6 +++
 include/ui/spice-display.h |  4 --
 hw/display/qxl.c   |  7 +++-
 ui/spice-core.c| 50 -
 ui/spice-display.c |  5 ++-
 ui/util.c  | 75 ++
 ui/meson.build |  1 +
 7 files changed, 92 insertions(+), 56 deletions(-)
 create mode 100644 ui/util.c

diff --git a/include/ui/console.h b/include/ui/console.h
index 7a35c4fc6a..b23ae283be 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -490,4 +490,10 @@ int index_from_key(const char *key, size_t key_length);
 int udmabuf_fd(void);
 #endif
 
+/* util.c */
+bool qemu_console_fill_device_address(QemuConsole *con,
+  char *device_address,
+  size_t size,
+  Error **errp);
+
 #endif
diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h
index a2fbf62c52..e271e011da 100644
--- a/include/ui/spice-display.h
+++ b/include/ui/spice-display.h
@@ -184,8 +184,4 @@ void qemu_spice_display_start(void);
 void qemu_spice_display_stop(void);
 int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd);
 
-bool qemu_spice_fill_device_address(QemuConsole *con,
-char *device_address,
-size_t size);
-
 #endif
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 29c80b4289..e2d6e317da 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2171,12 +2171,17 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error 
**errp)
 }
 
 #if SPICE_SERVER_VERSION >= 0x000e02 /* release 0.14.2 */
+Error *err = NULL;
 char device_address[256] = "";
-if (qemu_spice_fill_device_address(qxl->vga.con, device_address, 256)) {
+if (qemu_console_fill_device_address(qxl->vga.con,
+ device_address, 
sizeof(device_address),
+ )) {
 spice_qxl_set_device_info(>ssd.qxl,
   device_address,
   0,
   qxl->max_outputs);
+} else {
+error_report_err(err);
 }
 #endif
 
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 31974b8d6c..c3ac20ad43 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -884,56 +884,6 @@ bool qemu_spice_have_display_interface(QemuConsole *con)
 return false;
 }
 
-/*
- * Recursively (in reverse order) appends addresses of PCI devices as it moves
- * up in the PCI hierarchy.
- *
- * @returns true on success, false when the buffer wasn't large enough
- */
-static bool append_pci_address(char *buf, size_t buf_size, const PCIDevice 
*pci)
-{
-PCIBus *bus = pci_get_bus(pci);
-/*
- * equivalent to if (!pci_bus_is_root(bus)), but the function is not built
- * with PCI_CONFIG=n, avoid using an #ifdef by checking directly
- */
-if (bus->parent_dev != NULL) {
-append_pci_address(buf, buf_size, bus->parent_dev);
-}
-
-size_t len = strlen(buf);
-ssize_t written = snprintf(buf + len, buf_size - len, "/%02x.%x",
-PCI_SLOT(pci->devfn), PCI_FUNC(pci->devfn));
-
-return written > 0 && written < buf_size - len;
-}
-
-bool qemu_spice_fill_device_address(QemuConsole *con,
-char *device_address,
-size_t size)
-{
-DeviceState *dev = DEVICE(object_property_get_link(OBJECT(con),
-   "device",
-   _abort));
-PCIDevice *pci = (PCIDevice *) object_dynamic_cast(OBJECT(dev),
-   TYPE_PCI_DEVICE);
-
-if (pci == NULL) {
-warn_report("Setting device address of a display device to SPICE: "
-"Not a PCI device.");
-return false;
-}
-
-strncpy(device_address, "pci/", size);
-if (!append_pci_address(device_address, size, pci)) {
-warn_report("Setting device address of a display device to SPICE: "
-"Too many PCI devices in the chain.");
-return false;
-}
-
-return true;
-}
-
 int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con)
 {
 if (g_slist_find(spice_consoles, con)) {
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 798e0f6167..1043f47f94 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -1148,12 +1148,15 @@ static void qemu_spice_display_init_one(QemuConsole 
*con)
 qemu_spice_add_display_interface(>qxl, con);
 
 #if SPICE_SERVER_VERSION >= 0x000e02 /* release 0.14.2 */
+Error *err = NULL;
 char device_address[256] = "";
-if (qemu_spice_fill_device_address(con, device_address, 256)) {
+if 

[PATCH v2 20/37] scripts: teach modinfo to skip non-C sources

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 scripts/modinfo-collect.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/scripts/modinfo-collect.py b/scripts/modinfo-collect.py
index 4acb188c3e..61b90688c6 100755
--- a/scripts/modinfo-collect.py
+++ b/scripts/modinfo-collect.py
@@ -51,6 +51,9 @@ def main(args):
 with open('compile_commands.json') as f:
 compile_commands = json.load(f)
 for src in args:
+if not src.endswith('.c'):
+print("MODINFO_DEBUG skip %s" % src)
+continue
 print("MODINFO_DEBUG src %s" % src)
 command = find_command(src, target, compile_commands)
 cmdline = process_command(src, command)
-- 
2.33.0.721.g106298f7f9




[PATCH v2 22/37] backends: move dbus-vmstate1.xml to backends/

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Although not used by the backend itself, use a common location for
documentation and sharing purposes.

Signed-off-by: Marc-André Lureau 
---
 {tests/qtest => backends}/dbus-vmstate1.xml | 0
 tests/qtest/meson.build | 2 +-
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename {tests/qtest => backends}/dbus-vmstate1.xml (100%)

diff --git a/tests/qtest/dbus-vmstate1.xml b/backends/dbus-vmstate1.xml
similarity index 100%
rename from tests/qtest/dbus-vmstate1.xml
rename to backends/dbus-vmstate1.xml
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index c9d8458062..b6016aee48 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -93,7 +93,7 @@ if dbus_daemon.found() and 
config_host.has_key('GDBUS_CODEGEN')
   #qtests_i386 += ['dbus-vmstate-test']
   dbus_vmstate1 = custom_target('dbus-vmstate description',
 output: ['dbus-vmstate1.h', 'dbus-vmstate1.c'],
-input: files('dbus-vmstate1.xml'),
+input: meson.source_root() / 
'backends/dbus-vmstate1.xml',
 command: [config_host['GDBUS_CODEGEN'],
   '@INPUT@',
   '--interface-prefix', 'org.qemu',
-- 
2.33.0.721.g106298f7f9




[PATCH v2 13/37] ui: make gl_block use a counter

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Track multiple callers blocking requests.

Signed-off-by: Marc-André Lureau 
---
 ui/console.c | 17 +
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/ui/console.c b/ui/console.c
index 3c4012271c..8d641b9530 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -128,7 +128,7 @@ struct QemuConsole {
 DisplaySurface *surface;
 int dcls;
 DisplayChangeListener *gl;
-bool gl_block;
+int gl_block;
 int window_id;
 
 /* Graphic console state.  */
@@ -288,10 +288,19 @@ void graphic_hw_gl_block(QemuConsole *con, bool block)
 {
 assert(con != NULL);
 
-con->gl_block = block;
-if (con->hw_ops->gl_block) {
-con->hw_ops->gl_block(con->hw, block);
+if (block) {
+con->gl_block++;
+} else {
+con->gl_block--;
+}
+assert(con->gl_block >= 0);
+if (!con->hw_ops->gl_block) {
+return;
+}
+if ((block && con->gl_block != 1) || (!block && con->gl_block != 0)) {
+return;
 }
+con->hw_ops->gl_block(con->hw, block);
 }
 
 void graphic_hw_gl_flushed(QemuConsole *con)
-- 
2.33.0.721.g106298f7f9




[PATCH v2 17/37] ui: split the GL context in a different object

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

This will allow to have one GL context but a variable number of
listeners.

Signed-off-by: Marc-André Lureau 
---
 include/ui/console.h   | 34 ++
 include/ui/egl-context.h   |  6 +++---
 include/ui/gtk.h   | 11 ++-
 include/ui/sdl2.h  |  7 ---
 include/ui/spice-display.h |  1 +
 ui/console.c   | 26 --
 ui/egl-context.c   |  6 +++---
 ui/egl-headless.c  | 21 ++---
 ui/gtk-egl.c   | 10 +-
 ui/gtk-gl-area.c   |  8 
 ui/gtk.c   | 24 
 ui/sdl2-gl.c   | 10 +-
 ui/sdl2.c  | 13 +
 ui/spice-display.c | 18 +++---
 14 files changed, 119 insertions(+), 76 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index cd6f103bd9..7a35c4fc6a 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -174,6 +174,7 @@ typedef struct QemuDmaBuf {
 } QemuDmaBuf;
 
 typedef struct DisplayState DisplayState;
+typedef struct DisplayGLCtx DisplayGLCtx;
 
 typedef struct DisplayChangeListenerOps {
 const char *dpy_name;
@@ -208,16 +209,6 @@ typedef struct DisplayChangeListenerOps {
 void (*dpy_cursor_define)(DisplayChangeListener *dcl,
   QEMUCursor *cursor);
 
-/* required if GL */
-QEMUGLContext (*dpy_gl_ctx_create)(DisplayChangeListener *dcl,
-   QEMUGLParams *params);
-/* required if GL */
-void (*dpy_gl_ctx_destroy)(DisplayChangeListener *dcl,
-   QEMUGLContext ctx);
-/* required if GL */
-int (*dpy_gl_ctx_make_current)(DisplayChangeListener *dcl,
-   QEMUGLContext ctx);
-
 /* required if GL */
 void (*dpy_gl_scanout_disable)(DisplayChangeListener *dcl);
 /* required if GL */
@@ -258,6 +249,26 @@ struct DisplayChangeListener {
 QLIST_ENTRY(DisplayChangeListener) next;
 };
 
+typedef struct DisplayGLCtxOps {
+/*
+ * We only check if the GLCtx is compatible with a DCL via ops. A natural
+ * evolution of this would be a callback to check some runtime requirements
+ * and allow various DCL kinds.
+ */
+const DisplayChangeListenerOps *compatible_dcl;
+
+QEMUGLContext (*dpy_gl_ctx_create)(DisplayGLCtx *dgc,
+   QEMUGLParams *params);
+void (*dpy_gl_ctx_destroy)(DisplayGLCtx *dgc,
+   QEMUGLContext ctx);
+int (*dpy_gl_ctx_make_current)(DisplayGLCtx *dgc,
+   QEMUGLContext ctx);
+} DisplayGLCtxOps;
+
+struct DisplayGLCtx {
+const DisplayGLCtxOps *ops;
+};
+
 DisplayState *init_displaystate(void);
 DisplaySurface *qemu_create_displaysurface_from(int width, int height,
 pixman_format_code_t format,
@@ -404,8 +415,7 @@ void graphic_hw_gl_block(QemuConsole *con, bool block);
 
 void qemu_console_early_init(void);
 
-void qemu_console_set_display_gl_ctx(QemuConsole *con,
- DisplayChangeListener *dcl);
+void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *ctx);
 
 QemuConsole *qemu_console_lookup_by_index(unsigned int index);
 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
diff --git a/include/ui/egl-context.h b/include/ui/egl-context.h
index 9374fe41e3..c2761d747a 100644
--- a/include/ui/egl-context.h
+++ b/include/ui/egl-context.h
@@ -4,10 +4,10 @@
 #include "ui/console.h"
 #include "ui/egl-helpers.h"
 
-QEMUGLContext qemu_egl_create_context(DisplayChangeListener *dcl,
+QEMUGLContext qemu_egl_create_context(DisplayGLCtx *dgc,
   QEMUGLParams *params);
-void qemu_egl_destroy_context(DisplayChangeListener *dcl, QEMUGLContext ctx);
-int qemu_egl_make_context_current(DisplayChangeListener *dcl,
+void qemu_egl_destroy_context(DisplayGLCtx *dgc, QEMUGLContext ctx);
+int qemu_egl_make_context_current(DisplayGLCtx *dgc,
   QEMUGLContext ctx);
 
 #endif /* EGL_CONTEXT_H */
diff --git a/include/ui/gtk.h b/include/ui/gtk.h
index 7d22affd38..101b147d1b 100644
--- a/include/ui/gtk.h
+++ b/include/ui/gtk.h
@@ -35,6 +35,7 @@ typedef struct GtkDisplayState GtkDisplayState;
 
 typedef struct VirtualGfxConsole {
 GtkWidget *drawing_area;
+DisplayGLCtx dgc;
 DisplayChangeListener dcl;
 QKbdState *kbd;
 DisplaySurface *ds;
@@ -165,7 +166,7 @@ void gd_egl_update(DisplayChangeListener *dcl,
 void gd_egl_refresh(DisplayChangeListener *dcl);
 void gd_egl_switch(DisplayChangeListener *dcl,
DisplaySurface *surface);
-QEMUGLContext gd_egl_create_context(DisplayChangeListener *dcl,
+QEMUGLContext gd_egl_create_context(DisplayGLCtx *dgc,
 QEMUGLParams *params);
 void 

[PATCH v2 16/37] ui: dispatch GL events to all listeners

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

For now, only one listener can receive GL events. Let's dispatch to all
listeners. (preliminary check ensure there is a single listener now
during regitration, and in next patches, compatible listeners only)

Signed-off-by: Marc-André Lureau 
---
 ui/console.c | 58 +---
 1 file changed, 42 insertions(+), 16 deletions(-)

diff --git a/ui/console.c b/ui/console.c
index 016ace5029..75e432106b 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1882,8 +1882,12 @@ int dpy_gl_ctx_make_current(QemuConsole *con, 
QEMUGLContext ctx)
 
 void dpy_gl_scanout_disable(QemuConsole *con)
 {
-assert(con->gl);
-con->gl->ops->dpy_gl_scanout_disable(con->gl);
+DisplayState *s = con->ds;
+DisplayChangeListener *dcl;
+
+QLIST_FOREACH(dcl, >listeners, next) {
+dcl->ops->dpy_gl_scanout_disable(dcl);
+}
 }
 
 void dpy_gl_scanout_texture(QemuConsole *con,
@@ -1894,58 +1898,80 @@ void dpy_gl_scanout_texture(QemuConsole *con,
 uint32_t x, uint32_t y,
 uint32_t width, uint32_t height)
 {
-assert(con->gl);
-con->gl->ops->dpy_gl_scanout_texture(con->gl, backing_id,
+DisplayState *s = con->ds;
+DisplayChangeListener *dcl;
+
+QLIST_FOREACH(dcl, >listeners, next) {
+dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
  backing_y_0_top,
  backing_width, backing_height,
  x, y, width, height);
+}
 }
 
 void dpy_gl_scanout_dmabuf(QemuConsole *con,
QemuDmaBuf *dmabuf)
 {
-assert(con->gl);
-con->gl->ops->dpy_gl_scanout_dmabuf(con->gl, dmabuf);
+DisplayState *s = con->ds;
+DisplayChangeListener *dcl;
+
+QLIST_FOREACH(dcl, >listeners, next) {
+dcl->ops->dpy_gl_scanout_dmabuf(dcl, dmabuf);
+}
 }
 
 void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
   bool have_hot, uint32_t hot_x, uint32_t hot_y)
 {
-assert(con->gl);
+DisplayState *s = con->ds;
+DisplayChangeListener *dcl;
 
-if (con->gl->ops->dpy_gl_cursor_dmabuf) {
-con->gl->ops->dpy_gl_cursor_dmabuf(con->gl, dmabuf,
+QLIST_FOREACH(dcl, >listeners, next) {
+if (dcl->ops->dpy_gl_cursor_dmabuf) {
+dcl->ops->dpy_gl_cursor_dmabuf(dcl, dmabuf,
have_hot, hot_x, hot_y);
+}
 }
 }
 
 void dpy_gl_cursor_position(QemuConsole *con,
 uint32_t pos_x, uint32_t pos_y)
 {
-assert(con->gl);
+DisplayState *s = con->ds;
+DisplayChangeListener *dcl;
 
-if (con->gl->ops->dpy_gl_cursor_position) {
-con->gl->ops->dpy_gl_cursor_position(con->gl, pos_x, pos_y);
+QLIST_FOREACH(dcl, >listeners, next) {
+if (dcl->ops->dpy_gl_cursor_position) {
+dcl->ops->dpy_gl_cursor_position(dcl, pos_x, pos_y);
+}
 }
 }
 
 void dpy_gl_release_dmabuf(QemuConsole *con,
   QemuDmaBuf *dmabuf)
 {
-assert(con->gl);
+DisplayState *s = con->ds;
+DisplayChangeListener *dcl;
 
-if (con->gl->ops->dpy_gl_release_dmabuf) {
-con->gl->ops->dpy_gl_release_dmabuf(con->gl, dmabuf);
+QLIST_FOREACH(dcl, >listeners, next) {
+if (dcl->ops->dpy_gl_release_dmabuf) {
+dcl->ops->dpy_gl_release_dmabuf(dcl, dmabuf);
+}
 }
 }
 
 void dpy_gl_update(QemuConsole *con,
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
 {
+DisplayState *s = con->ds;
+DisplayChangeListener *dcl;
+
 assert(con->gl);
 
 graphic_hw_gl_block(con, true);
-con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
+QLIST_FOREACH(dcl, >listeners, next) {
+dcl->ops->dpy_gl_update(dcl, x, y, w, h);
+}
 graphic_hw_gl_block(con, false);
 }
 
-- 
2.33.0.721.g106298f7f9




[PATCH v2 21/37] docs/sphinx: add sphinx modules to include D-Bus documentation

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Add a new dbus-doc directive to import D-Bus interfaces documentation
from the introspection XML. The comments annotations follow the
gtkdoc/kerneldoc style, and should be formatted with reST.

Note: I realize after the fact that I was implementing those modules
with sphinx 4, and that we have much lower requirements. Instead of
lowering the features and code (removing type annotations etc), I
propose to have a warning in the documentation when the D-Bus modules
can't be used, and point to the source XML file in that case.

Signed-off-by: Marc-André Lureau 
---
 docs/conf.py   |   8 +
 docs/sphinx/dbusdoc.py | 166 +++
 docs/sphinx/dbusdomain.py  | 406 +
 docs/sphinx/dbusparser.py  | 373 ++
 docs/sphinx/fakedbusdoc.py |  25 +++
 5 files changed, 978 insertions(+)
 create mode 100644 docs/sphinx/dbusdoc.py
 create mode 100644 docs/sphinx/dbusdomain.py
 create mode 100644 docs/sphinx/dbusparser.py
 create mode 100644 docs/sphinx/fakedbusdoc.py

diff --git a/docs/conf.py b/docs/conf.py
index ff6e92c6e2..71e2369026 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -73,6 +73,12 @@
 # ones.
 extensions = ['kerneldoc', 'qmp_lexer', 'hxtool', 'depfile', 'qapidoc']
 
+if sphinx.version_info[:3] > (4, 0, 0):
+tags.add('sphinx4')
+extensions += ['dbusdoc']
+else:
+extensions += ['fakedbusdoc']
+
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
 
@@ -301,3 +307,5 @@
 kerneldoc_srctree = os.path.join(qemu_docdir, '..')
 hxtool_srctree = os.path.join(qemu_docdir, '..')
 qapidoc_srctree = os.path.join(qemu_docdir, '..')
+dbusdoc_srctree = os.path.join(qemu_docdir, '..')
+dbus_index_common_prefix = ["org.qemu."]
diff --git a/docs/sphinx/dbusdoc.py b/docs/sphinx/dbusdoc.py
new file mode 100644
index 00..be284ed08f
--- /dev/null
+++ b/docs/sphinx/dbusdoc.py
@@ -0,0 +1,166 @@
+# D-Bus XML documentation extension
+#
+# Copyright (C) 2021, Red Hat Inc.
+#
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Author: Marc-André Lureau 
+"""dbus-doc is a Sphinx extension that provides documentation from D-Bus 
XML."""
+
+import os
+import re
+from typing import (
+TYPE_CHECKING,
+Any,
+Callable,
+Dict,
+Iterator,
+List,
+Optional,
+Sequence,
+Set,
+Tuple,
+Type,
+TypeVar,
+Union,
+)
+
+import sphinx
+from docutils import nodes
+from docutils.nodes import Element, Node
+from docutils.parsers.rst import Directive, directives
+from docutils.parsers.rst.states import RSTState
+from docutils.statemachine import StringList, ViewList
+from sphinx.application import Sphinx
+from sphinx.errors import ExtensionError
+from sphinx.util import logging
+from sphinx.util.docstrings import prepare_docstring
+from sphinx.util.docutils import SphinxDirective, switch_source_input
+from sphinx.util.nodes import nested_parse_with_titles
+
+import dbusdomain
+from dbusparser import parse_dbus_xml
+
+logger = logging.getLogger(__name__)
+
+__version__ = "1.0"
+
+
+class DBusDoc:
+def __init__(self, sphinx_directive, dbusfile):
+self._cur_doc = None
+self._sphinx_directive = sphinx_directive
+self._dbusfile = dbusfile
+self._top_node = nodes.section()
+self.result = StringList()
+self.indent = ""
+
+def add_line(self, line: str, *lineno: int) -> None:
+"""Append one line of generated reST to the output."""
+if line.strip():  # not a blank line
+self.result.append(self.indent + line, self._dbusfile, *lineno)
+else:
+self.result.append("", self._dbusfile, *lineno)
+
+def add_method(self, method):
+self.add_line(f".. dbus:method:: {method.name}")
+self.add_line("")
+self.indent += "   "
+for arg in method.in_args:
+self.add_line(f":arg {arg.signature} {arg.name}: {arg.doc_string}")
+for arg in method.out_args:
+self.add_line(f":ret {arg.signature} {arg.name}: {arg.doc_string}")
+self.add_line("")
+for line in prepare_docstring("\n" + method.doc_string):
+self.add_line(line)
+self.indent = self.indent[:-3]
+
+def add_signal(self, signal):
+self.add_line(f".. dbus:signal:: {signal.name}")
+self.add_line("")
+self.indent += "   "
+for arg in signal.args:
+self.add_line(f":arg {arg.signature} {arg.name}: {arg.doc_string}")
+self.add_line("")
+for line in prepare_docstring("\n" + signal.doc_string):
+self.add_line(line)
+self.indent = self.indent[:-3]
+
+def add_property(self, prop):
+self.add_line(f".. dbus:property:: {prop.name}")
+self.indent += "   "
+self.add_line(f":type: {prop.signature}")
+access = {"read": "readonly", "write": "writeonly", "readwrite": 
"readwrite"}[
+

[PATCH v2 15/37] ui: simplify gl unblock & flush

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

GraphicHw.gl_flushed was introduced to notify the
device (vhost-user-gpu) that the GL resources (the display scanout) are
no longer needed.

It was decoupled from QEMU own gl-blocking mechanism, but that
difference isn't helping. Instead, we can reuse QEMU gl-blocking and
notify virtio_gpu_gl_flushed() when unblocking (to unlock
vhost-user-gpu).

An extra block/unblock is added arount dpy_gl_update() so existing
backends that don't block will have the flush event handled. It will
also help when there are no backends associated.

Signed-off-by: Marc-André Lureau 
---
 include/ui/console.h |  2 --
 hw/display/vhost-user-gpu.c  |  2 +-
 hw/display/virtio-gpu-base.c |  5 -
 hw/display/virtio-vga.c  | 11 ---
 ui/console.c | 12 +++-
 ui/gtk-egl.c |  1 -
 ui/gtk-gl-area.c |  1 -
 ui/gtk.c |  1 -
 ui/sdl2-gl.c |  2 --
 ui/spice-display.c   |  1 -
 10 files changed, 8 insertions(+), 30 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 1617b4c59a..cd6f103bd9 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -386,7 +386,6 @@ typedef struct GraphicHwOps {
 void (*update_interval)(void *opaque, uint64_t interval);
 int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
 void (*gl_block)(void *opaque, bool block);
-void (*gl_flushed)(void *opaque);
 } GraphicHwOps;
 
 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
@@ -402,7 +401,6 @@ void graphic_hw_update_done(QemuConsole *con);
 void graphic_hw_invalidate(QemuConsole *con);
 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
 void graphic_hw_gl_block(QemuConsole *con, bool block);
-void graphic_hw_gl_flushed(QemuConsole *con);
 
 void qemu_console_early_init(void);
 
diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index 49df56cd14..09818231bd 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -254,8 +254,8 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, 
VhostUserGpuMsg *msg)
 vhost_user_gpu_unblock(g);
 break;
 }
-dpy_gl_update(con, m->x, m->y, m->width, m->height);
 g->backend_blocked = true;
+dpy_gl_update(con, m->x, m->y, m->width, m->height);
 break;
 }
 case VHOST_USER_GPU_UPDATE: {
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index c8da4806e0..fff0fb4a82 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -117,6 +117,10 @@ virtio_gpu_gl_block(void *opaque, bool block)
 g->renderer_blocked--;
 }
 assert(g->renderer_blocked >= 0);
+
+if (!block && g->renderer_blocked == 0) {
+virtio_gpu_gl_flushed(g);
+}
 }
 
 static int
@@ -143,7 +147,6 @@ static const GraphicHwOps virtio_gpu_ops = {
 .text_update = virtio_gpu_text_update,
 .ui_info = virtio_gpu_ui_info,
 .gl_block = virtio_gpu_gl_block,
-.gl_flushed = virtio_gpu_gl_flushed,
 };
 
 bool
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 9e57f61e9e..b23a75a04b 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -68,16 +68,6 @@ static void virtio_vga_base_gl_block(void *opaque, bool 
block)
 }
 }
 
-static void virtio_vga_base_gl_flushed(void *opaque)
-{
-VirtIOVGABase *vvga = opaque;
-VirtIOGPUBase *g = vvga->vgpu;
-
-if (g->hw_ops->gl_flushed) {
-g->hw_ops->gl_flushed(g);
-}
-}
-
 static int virtio_vga_base_get_flags(void *opaque)
 {
 VirtIOVGABase *vvga = opaque;
@@ -93,7 +83,6 @@ static const GraphicHwOps virtio_vga_base_ops = {
 .text_update = virtio_vga_base_text_update,
 .ui_info = virtio_vga_base_ui_info,
 .gl_block = virtio_vga_base_gl_block,
-.gl_flushed = virtio_vga_base_gl_flushed,
 };
 
 static const VMStateDescription vmstate_virtio_vga_base = {
diff --git a/ui/console.c b/ui/console.c
index c62a33b1ec..016ace5029 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -318,15 +318,6 @@ void graphic_hw_gl_block(QemuConsole *con, bool block)
 }
 }
 
-void graphic_hw_gl_flushed(QemuConsole *con)
-{
-assert(con != NULL);
-
-if (con->hw_ops->gl_flushed) {
-con->hw_ops->gl_flushed(con->hw);
-}
-}
-
 int qemu_console_get_window_id(QemuConsole *con)
 {
 return con->window_id;
@@ -1952,7 +1943,10 @@ void dpy_gl_update(QemuConsole *con,
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
 {
 assert(con->gl);
+
+graphic_hw_gl_block(con, true);
 con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
+graphic_hw_gl_block(con, false);
 }
 
 /***/
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 72ce5e1f8f..0f64baee63 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -107,7 +107,6 @@ void gd_egl_draw(VirtualConsole *vc)
 

[PATCH v2 12/37] ui: associate GL context outside of display listener registration

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 ui/console.c   | 7 +--
 ui/egl-headless.c  | 1 +
 ui/gtk.c   | 3 +++
 ui/sdl2.c  | 3 +++
 ui/spice-display.c | 3 +++
 5 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/ui/console.c b/ui/console.c
index 64f35e163c..3c4012271c 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1523,8 +1523,11 @@ void 
register_displaychangelistener(DisplayChangeListener *dcl)
 
 assert(!dcl->ds);
 
-if (dcl->ops->dpy_gl_ctx_create) {
-qemu_console_set_display_gl_ctx(dcl->con, dcl);
+if (dcl->con && dcl->con->gl &&
+dcl->con->gl != dcl) {
+error_report("Display %s is incompatible with the GL context",
+ dcl->ops->dpy_name);
+exit(1);
 }
 
 if (dcl->con) {
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index a26a2520c4..08327c40c6 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -197,6 +197,7 @@ static void egl_headless_init(DisplayState *ds, 
DisplayOptions *opts)
 edpy->dcl.con = con;
 edpy->dcl.ops = _ops;
 edpy->gls = qemu_gl_init_shader();
+qemu_console_set_display_gl_ctx(con, >dcl);
 register_displaychangelistener(>dcl);
 }
 }
diff --git a/ui/gtk.c b/ui/gtk.c
index 163b6bcb6a..f8beddbb91 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -2057,6 +2057,9 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, 
VirtualConsole *vc,
 vc->gfx.kbd = qkbd_state_init(con);
 vc->gfx.dcl.con = con;
 
+if (display_opengl) {
+qemu_console_set_display_gl_ctx(con, >gfx.dcl);
+}
 register_displaychangelistener(>gfx.dcl);
 
 gd_connect_vc_gfx_signals(vc);
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 9ba3bc49e7..bb186a381a 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -866,6 +866,9 @@ static void sdl2_display_init(DisplayState *ds, 
DisplayOptions *o)
 #endif
 sdl2_console[i].dcl.con = con;
 sdl2_console[i].kbd = qkbd_state_init(con);
+if (display_opengl) {
+qemu_console_set_display_gl_ctx(con, _console[i].dcl);
+}
 register_displaychangelistener(_console[i].dcl);
 
 #if defined(SDL_VIDEO_DRIVER_WINDOWS) || defined(SDL_VIDEO_DRIVER_X11)
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 52d9f3260a..2c204bceee 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -1156,6 +1156,9 @@ static void qemu_spice_display_init_one(QemuConsole *con)
 
 qemu_spice_create_host_memslot(ssd);
 
+if (spice_opengl) {
+qemu_console_set_display_gl_ctx(con, >dcl);
+}
 register_displaychangelistener(>dcl);
 }
 
-- 
2.33.0.721.g106298f7f9




[PATCH v2 08/37] hw/display: report an error if virgl initialization failed

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Currently, virgl initialization error is silent. Make it verbose instead.

(this is likely going to bug later on, as the device isn't fully
initialized)

Signed-off-by: Marc-André Lureau 
---
 hw/display/virtio-gpu-virgl.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 18d054922f..0d87de65d7 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -609,6 +609,7 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
 
 ret = virgl_renderer_init(g, 0, _gpu_3d_cbs);
 if (ret != 0) {
+error_report("virgl could not be initialized: %d", ret);
 return ret;
 }
 
-- 
2.33.0.721.g106298f7f9




[PATCH v2 19/37] console: save current scanout details

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Add a new DisplayScanout structure to save the current scanout details.
This allows to attach later UI backends and set the scanout.

Introduce displaychangelistener_display_console() helper function to
handle the dpy_gfx_switch/gl_scanout() & dpy_gfx_update() calls.

Signed-off-by: Marc-André Lureau 
---
 include/ui/console.h |  27 +++
 ui/console.c | 165 +--
 2 files changed, 138 insertions(+), 54 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index b23ae283be..ab55d71894 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -108,6 +108,17 @@ struct QemuConsoleClass {
 #define QEMU_ALLOCATED_FLAG 0x01
 #define QEMU_PLACEHOLDER_FLAG   0x02
 
+typedef struct ScanoutTexture {
+uint32_t backing_id;
+bool backing_y_0_top;
+uint32_t backing_width;
+uint32_t backing_height;
+uint32_t x;
+uint32_t y;
+uint32_t width;
+uint32_t height;
+} ScanoutTexture;
+
 typedef struct DisplaySurface {
 pixman_format_code_t format;
 pixman_image_t *image;
@@ -173,6 +184,22 @@ typedef struct QemuDmaBuf {
 bool  allow_fences;
 } QemuDmaBuf;
 
+enum display_scanout {
+SCANOUT_NONE,
+SCANOUT_SURFACE,
+SCANOUT_TEXTURE,
+SCANOUT_DMABUF,
+};
+
+typedef struct DisplayScanout {
+enum display_scanout kind;
+union {
+/* DisplaySurface *surface; is kept in QemuConsole */
+ScanoutTexture texture;
+QemuDmaBuf *dmabuf;
+};
+} DisplayScanout;
+
 typedef struct DisplayState DisplayState;
 typedef struct DisplayGLCtx DisplayGLCtx;
 
diff --git a/ui/console.c b/ui/console.c
index e5a2c84dd9..a1c6a78523 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -126,6 +126,7 @@ struct QemuConsole {
 console_type_t console_type;
 DisplayState *ds;
 DisplaySurface *surface;
+DisplayScanout scanout;
 int dcls;
 DisplayGLCtx *gl;
 int gl_block;
@@ -197,6 +198,7 @@ static void dpy_refresh(DisplayState *s);
 static DisplayState *get_alloc_displaystate(void);
 static void text_console_update_cursor_timer(void);
 static void text_console_update_cursor(void *opaque);
+static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
 
 static void gui_update(void *opaque)
 {
@@ -532,6 +534,8 @@ static void text_console_resize(QemuConsole *s)
 TextCell *cells, *c, *c1;
 int w1, x, y, last_width;
 
+assert(s->scanout.kind == SCANOUT_SURFACE);
+
 last_width = s->width;
 s->width = surface_width(s->surface) / FONT_WIDTH;
 s->height = surface_height(s->surface) / FONT_HEIGHT;
@@ -1103,6 +1107,48 @@ static void console_putchar(QemuConsole *s, int ch)
 }
 }
 
+static void displaychangelistener_display_console(DisplayChangeListener *dcl,
+  QemuConsole *con)
+{
+static const char nodev[] =
+"This VM has no graphic display device.";
+static DisplaySurface *dummy;
+
+if (!con) {
+if (!dcl->ops->dpy_gfx_switch) {
+return;
+}
+if (!dummy) {
+dummy = qemu_create_placeholder_surface(640, 480, nodev);
+}
+dcl->ops->dpy_gfx_switch(dcl, dummy);
+return;
+}
+
+if (con->scanout.kind == SCANOUT_DMABUF &&
+displaychangelistener_has_dmabuf(dcl)) {
+dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf);
+} else if (con->scanout.kind == SCANOUT_TEXTURE &&
+   dcl->ops->dpy_gl_scanout_texture) {
+dcl->ops->dpy_gl_scanout_texture(dcl,
+ con->scanout.texture.backing_id,
+ con->scanout.texture.backing_y_0_top,
+ con->scanout.texture.backing_width,
+ con->scanout.texture.backing_height,
+ con->scanout.texture.x,
+ con->scanout.texture.y,
+ con->scanout.texture.width,
+ con->scanout.texture.height);
+} else if (con->scanout.kind == SCANOUT_SURFACE &&
+   dcl->ops->dpy_gfx_switch) {
+dcl->ops->dpy_gfx_switch(dcl, con->surface);
+}
+
+dcl->ops->dpy_gfx_update(dcl, 0, 0,
+ qemu_console_get_width(con, 0),
+ qemu_console_get_height(con, 0));
+}
+
 void console_select(unsigned int index)
 {
 DisplayChangeListener *dcl;
@@ -1119,13 +1165,7 @@ void console_select(unsigned int index)
 if (dcl->con != NULL) {
 continue;
 }
-if (dcl->ops->dpy_gfx_switch) {
-dcl->ops->dpy_gfx_switch(dcl, s->surface);
-}
-}
-if (s->surface) {
-dpy_gfx_update(s, 0, 0, surface_width(s->surface),
-  

[PATCH v2 07/37] ui/clipboard: add a clipboard reset serial event

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 include/ui/clipboard.h |  9 +
 ui/clipboard.c |  7 +++
 ui/gtk-clipboard.c |  3 +++
 ui/vdagent.c   | 12 
 ui/vnc-clipboard.c |  3 +++
 ui/cocoa.m |  3 +++
 6 files changed, 37 insertions(+)

diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h
index 2c6488c1ee..ce76aa451f 100644
--- a/include/ui/clipboard.h
+++ b/include/ui/clipboard.h
@@ -73,11 +73,13 @@ struct QemuClipboardPeer {
  * enum QemuClipboardNotifyType
  *
  * @QEMU_CLIPBOARD_UPDATE_INFO: clipboard info update
+ * @QEMU_CLIPBOARD_RESET_SERIAL: reset clipboard serial
  *
  * Clipboard notify type.
  */
 enum QemuClipboardNotifyType {
 QEMU_CLIPBOARD_UPDATE_INFO,
+QEMU_CLIPBOARD_RESET_SERIAL,
 };
 
 /**
@@ -230,6 +232,13 @@ void qemu_clipboard_info_unref(QemuClipboardInfo *info);
  */
 void qemu_clipboard_update(QemuClipboardInfo *info);
 
+/**
+ * qemu_clipboard_reset_serial
+ *
+ * Reset the clipboard serial.
+ */
+void qemu_clipboard_reset_serial(void);
+
 /**
  * qemu_clipboard_request
  *
diff --git a/ui/clipboard.c b/ui/clipboard.c
index ffbd80e5c6..82572ea116 100644
--- a/ui/clipboard.c
+++ b/ui/clipboard.c
@@ -129,6 +129,13 @@ void qemu_clipboard_request(QemuClipboardInfo *info,
 info->owner->request(info, type);
 }
 
+void qemu_clipboard_reset_serial(void)
+{
+QemuClipboardNotify notify = { .type = QEMU_CLIPBOARD_RESET_SERIAL };
+
+notifier_list_notify(_notifiers, );
+}
+
 void qemu_clipboard_set_data(QemuClipboardPeer *peer,
  QemuClipboardInfo *info,
  QemuClipboardType type,
diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c
index 44ff810234..e0b8b283fe 100644
--- a/ui/gtk-clipboard.c
+++ b/ui/gtk-clipboard.c
@@ -127,6 +127,9 @@ static void gd_clipboard_notify(Notifier *notifier, void 
*data)
 case QEMU_CLIPBOARD_UPDATE_INFO:
 gd_clipboard_update_info(gd, notify->info);
 return;
+case QEMU_CLIPBOARD_RESET_SERIAL:
+/* ignore */
+return;
 }
 }
 
diff --git a/ui/vdagent.c b/ui/vdagent.c
index b4fdae6917..7ea4bc5d9a 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -466,6 +466,15 @@ static void vdagent_clipboard_update_info(VDAgentChardev 
*vd,
 }
 }
 
+static void vdagent_clipboard_reset_serial(VDAgentChardev *vd)
+{
+Chardev *chr = CHARDEV(vd);
+
+/* reopen the agent connection to reset the serial state */
+qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
+qemu_chr_be_event(chr, CHR_EVENT_OPENED);
+}
+
 static void vdagent_clipboard_notify(Notifier *notifier, void *data)
 {
 VDAgentChardev *vd =
@@ -476,6 +485,9 @@ static void vdagent_clipboard_notify(Notifier *notifier, 
void *data)
 case QEMU_CLIPBOARD_UPDATE_INFO:
 vdagent_clipboard_update_info(vd, notify->info);
 return;
+case QEMU_CLIPBOARD_RESET_SERIAL:
+vdagent_clipboard_reset_serial(vd);
+return;
 }
 }
 
diff --git a/ui/vnc-clipboard.c b/ui/vnc-clipboard.c
index 41aeff1085..8b2dd0a64a 100644
--- a/ui/vnc-clipboard.c
+++ b/ui/vnc-clipboard.c
@@ -230,6 +230,9 @@ static void vnc_clipboard_notify(Notifier *notifier, void 
*data)
 case QEMU_CLIPBOARD_UPDATE_INFO:
 vnc_clipboard_update_info(vs, notify->info);
 return;
+case QEMU_CLIPBOARD_RESET_SERIAL:
+/* ignore */
+return;
 }
 }
 
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 6745e3fc8c..69b6c07d53 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -1837,6 +1837,9 @@ static void cocoa_clipboard_notify(Notifier *notifier, 
void *data)
 case QEMU_CLIPBOARD_UPDATE_INFO:
 cocoa_clipboard_update_info(notify->info);
 return;
+case QEMU_CLIPBOARD_RESET_SERIAL:
+/* ignore */
+return;
 }
 }
 
-- 
2.33.0.721.g106298f7f9




[PATCH v2 11/37] ui: factor out qemu_console_set_display_gl_ctx()

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

The next patch will make use of this function to dissociate
DisplayChangeListener from GL context.

Signed-off-by: Marc-André Lureau 
---
 include/ui/console.h |  3 +++
 ui/console.c | 22 ++
 2 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 7b2f624e93..1617b4c59a 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -406,6 +406,9 @@ void graphic_hw_gl_flushed(QemuConsole *con);
 
 void qemu_console_early_init(void);
 
+void qemu_console_set_display_gl_ctx(QemuConsole *con,
+ DisplayChangeListener *dcl);
+
 QemuConsole *qemu_console_lookup_by_index(unsigned int index);
 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
diff --git a/ui/console.c b/ui/console.c
index 7eea1fc641..64f35e163c 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1501,6 +1501,19 @@ static bool dpy_compatible_with(QemuConsole *con,
 return true;
 }
 
+void qemu_console_set_display_gl_ctx(QemuConsole *con,
+ DisplayChangeListener *dcl)
+{
+/* display has opengl support */
+assert(dcl->con);
+if (dcl->con->gl) {
+fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
+dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
+exit(1);
+}
+dcl->con->gl = dcl;
+}
+
 void register_displaychangelistener(DisplayChangeListener *dcl)
 {
 static const char nodev[] =
@@ -1511,14 +1524,7 @@ void 
register_displaychangelistener(DisplayChangeListener *dcl)
 assert(!dcl->ds);
 
 if (dcl->ops->dpy_gl_ctx_create) {
-/* display has opengl support */
-assert(dcl->con);
-if (dcl->con->gl) {
-fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
-dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
-exit(1);
-}
-dcl->con->gl = dcl;
+qemu_console_set_display_gl_ctx(dcl->con, dcl);
 }
 
 if (dcl->con) {
-- 
2.33.0.721.g106298f7f9




[PATCH v2 06/37] ui/clipboard: add qemu_clipboard_check_serial()

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 include/ui/clipboard.h | 10 ++
 ui/clipboard.c | 15 +++
 2 files changed, 25 insertions(+)

diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h
index e590b453c8..2c6488c1ee 100644
--- a/include/ui/clipboard.h
+++ b/include/ui/clipboard.h
@@ -172,6 +172,16 @@ void qemu_clipboard_peer_release(QemuClipboardPeer *peer,
  */
 QemuClipboardInfo *qemu_clipboard_info(QemuClipboardSelection selection);
 
+/**
+ * qemu_clipboard_check_serial
+ *
+ * @info: clipboard info.
+ * @client: whether to check from the client context and priority.
+ *
+ * Return TRUE if the @info has a higher serial than the current clipboard.
+ */
+bool qemu_clipboard_check_serial(QemuClipboardInfo *info, bool client);
+
 /**
  * qemu_clipboard_info_new
  *
diff --git a/ui/clipboard.c b/ui/clipboard.c
index 743b39edf4..ffbd80e5c6 100644
--- a/ui/clipboard.c
+++ b/ui/clipboard.c
@@ -41,6 +41,21 @@ void qemu_clipboard_peer_release(QemuClipboardPeer *peer,
 }
 }
 
+bool qemu_clipboard_check_serial(QemuClipboardInfo *info, bool client)
+{
+if (!info->has_serial ||
+!cbinfo[info->selection] ||
+!cbinfo[info->selection]->has_serial) {
+return true;
+}
+
+if (client) {
+return cbinfo[info->selection]->serial >= info->serial;
+} else {
+return cbinfo[info->selection]->serial > info->serial;
+}
+}
+
 void qemu_clipboard_update(QemuClipboardInfo *info)
 {
 QemuClipboardNotify notify = {
-- 
2.33.0.721.g106298f7f9




[PATCH v2 09/37] virtio-gpu: use VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 hw/display/virtio-gpu-virgl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 0d87de65d7..73cb92c8d5 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -175,7 +175,7 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
 virgl_renderer_force_ctx_0();
 dpy_gl_scanout_texture(
 g->parent_obj.scanout[ss.scanout_id].con, info.tex_id,
-info.flags & 1 /* FIXME: Y_0_TOP */,
+info.flags & VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP,
 info.width, info.height,
 ss.r.x, ss.r.y, ss.r.width, ss.r.height);
 } else {
-- 
2.33.0.721.g106298f7f9




[PATCH v2 05/37] ui/vdagent: add serial capability support

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

The Spice agent implements a simple serial mechanism to avoid clipboard
races between client & guest. See:
https://gitlab.freedesktop.org/spice/spice-protocol/-/commit/045a6978d6dbbf7046affc5c321fa8177c8cce56

Signed-off-by: Marc-André Lureau 
---
 include/ui/clipboard.h |  4 
 ui/vdagent.c   | 39 ++-
 ui/trace-events|  1 +
 3 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h
index d82cf31481..e590b453c8 100644
--- a/include/ui/clipboard.h
+++ b/include/ui/clipboard.h
@@ -102,6 +102,8 @@ struct QemuClipboardNotify {
  * @owner: clipboard owner.
  * @selection: clipboard selection.
  * @types: clipboard data array (one entry per type).
+ * @has_serial: whether @serial is available.
+ * @serial: the grab serial counter.
  *
  * Clipboard content data and metadata.
  */
@@ -109,6 +111,8 @@ struct QemuClipboardInfo {
 uint32_t refcount;
 QemuClipboardPeer *owner;
 QemuClipboardSelection selection;
+bool has_serial;
+uint32_t serial;
 struct {
 bool available;
 bool requested;
diff --git a/ui/vdagent.c b/ui/vdagent.c
index de827aad27..b4fdae6917 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -59,6 +59,7 @@ struct VDAgentChardev {
 
 /* clipboard */
 QemuClipboardPeer cbpeer;
+uint32_t last_serial[QEMU_CLIPBOARD_SELECTION__COUNT];
 uint32_t cbpending[QEMU_CLIPBOARD_SELECTION__COUNT];
 };
 typedef struct VDAgentChardev VDAgentChardev;
@@ -203,6 +204,9 @@ static void vdagent_send_caps(VDAgentChardev *vd)
 if (vd->clipboard) {
 caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
 caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION);
+#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
+caps->caps[0] |= (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL);
+#endif
 }
 
 vdagent_send_msg(vd, msg);
@@ -333,7 +337,8 @@ static void vdagent_send_clipboard_grab(VDAgentChardev *vd,
 {
 g_autofree VDAgentMessage *msg =
 g_malloc0(sizeof(VDAgentMessage) +
-  sizeof(uint32_t) * (QEMU_CLIPBOARD_TYPE__COUNT + 1));
+  sizeof(uint32_t) * (QEMU_CLIPBOARD_TYPE__COUNT + 1) +
+  sizeof(uint32_t));
 uint8_t *s = msg->data;
 uint32_t *data = (uint32_t *)msg->data;
 uint32_t q, type;
@@ -346,6 +351,19 @@ static void vdagent_send_clipboard_grab(VDAgentChardev *vd,
 return;
 }
 
+#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
+if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
+if (!info->has_serial) {
+/* client should win */
+info->serial = vd->last_serial[info->selection]++;
+info->has_serial = true;
+}
+*data = info->serial;
+data++;
+msg->size += sizeof(uint32_t);
+}
+#endif
+
 for (q = 0; q < QEMU_CLIPBOARD_TYPE__COUNT; q++) {
 type = type_qemu_to_vdagent(q);
 if (type != VD_AGENT_CLIPBOARD_NONE && info->types[q].available) {
@@ -494,6 +512,24 @@ static void vdagent_clipboard_recv_grab(VDAgentChardev 
*vd, uint8_t s, uint32_t
 
 trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s));
 info = qemu_clipboard_info_new(>cbpeer, s);
+#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
+if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) {
+if (size < sizeof(uint32_t)) {
+/* this shouldn't happen! */
+return;
+}
+
+info->has_serial = true;
+info->serial = *(uint32_t *)data;
+if (info->serial < vd->last_serial[s]) {
+/* discard lower-ordering guest grab */
+return;
+}
+vd->last_serial[s] = info->serial;
+data += sizeof(uint32_t);
+size -= sizeof(uint32_t);
+}
+#endif
 if (size > sizeof(uint32_t) * 10) {
 /*
  * spice has 6 types as of 2021. Limiting to 10 entries
@@ -671,6 +707,7 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, 
VDAgentMessage *msg)
 qemu_input_handler_activate(vd->mouse_hs);
 }
 if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) {
+memset(vd->last_serial, 0, sizeof(vd->last_serial));
 vd->cbpeer.name = "vdagent";
 vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
 vd->cbpeer.request = vdagent_clipboard_request;
diff --git a/ui/trace-events b/ui/trace-events
index b9c0dd0fa1..e832c3e365 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -135,3 +135,4 @@ vdagent_recv_msg(const char *name, uint32_t size) "msg %s, 
size %d"
 vdagent_peer_cap(const char *name) "cap %s"
 vdagent_cb_grab_selection(const char *name) "selection %s"
 vdagent_cb_grab_type(const char *name) "type %s"
+vdagent_cb_serial_discard(uint32_t current, uint32_t received) "current=%u, 
received=%u"
-- 
2.33.0.721.g106298f7f9




[PATCH v2 10/37] ui: do not delay further remote resize

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

A remote client, such as Spice, will already avoid flooding the stream
by delaying the resize requests.

Signed-off-by: Marc-André Lureau 
---
 include/ui/console.h | 2 +-
 ui/console.c | 5 +++--
 ui/gtk.c | 2 +-
 ui/sdl2.c| 2 +-
 ui/spice-display.c   | 2 +-
 ui/vnc.c | 2 +-
 6 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/include/ui/console.h b/include/ui/console.h
index 244664d727..7b2f624e93 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -287,7 +287,7 @@ void unregister_displaychangelistener(DisplayChangeListener 
*dcl);
 
 bool dpy_ui_info_supported(QemuConsole *con);
 const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con);
-int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info);
+int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay);
 
 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
 void dpy_gfx_update_full(QemuConsole *con);
diff --git a/ui/console.c b/ui/console.c
index eabbbc951c..7eea1fc641 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1596,7 +1596,7 @@ const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
 return >ui_info;
 }
 
-int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
+int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
 {
 if (con == NULL) {
 con = active_console;
@@ -1616,7 +1616,8 @@ int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
  * go notify the guest.
  */
 con->ui_info = *info;
-timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
+timer_mod(con->ui_timer,
+  qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + (delay ? 1000 : 0));
 return 0;
 }
 
diff --git a/ui/gtk.c b/ui/gtk.c
index b0564d80c1..163b6bcb6a 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -698,7 +698,7 @@ static void gd_set_ui_info(VirtualConsole *vc, gint width, 
gint height)
 memset(, 0, sizeof(info));
 info.width = width;
 info.height = height;
-dpy_set_ui_info(vc->gfx.dcl.con, );
+dpy_set_ui_info(vc->gfx.dcl.con, , true);
 }
 
 #if defined(CONFIG_OPENGL)
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 17c0ec30eb..9ba3bc49e7 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -561,7 +561,7 @@ static void handle_windowevent(SDL_Event *ev)
 memset(, 0, sizeof(info));
 info.width = ev->window.data1;
 info.height = ev->window.data2;
-dpy_set_ui_info(scon->dcl.con, );
+dpy_set_ui_info(scon->dcl.con, , true);
 }
 sdl2_redraw(scon);
 break;
diff --git a/ui/spice-display.c b/ui/spice-display.c
index f59c69882d..52d9f3260a 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -692,7 +692,7 @@ static int interface_client_monitors_config(QXLInstance 
*sin,
 }
 
 trace_qemu_spice_ui_info(ssd->qxl.id, info.width, info.height);
-dpy_set_ui_info(ssd->dcl.con, );
+dpy_set_ui_info(ssd->dcl.con, , false);
 return 1;
 }
 
diff --git a/ui/vnc.c b/ui/vnc.c
index 9b603382e7..1ed1c7efc6 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2596,7 +2596,7 @@ static int protocol_client_msg(VncState *vs, uint8_t 
*data, size_t len)
 memset(, 0, sizeof(info));
 info.width = w;
 info.height = h;
-dpy_set_ui_info(vs->vd->dcl.con, );
+dpy_set_ui_info(vs->vd->dcl.con, , false);
 vnc_desktop_resize_ext(vs, 4 /* Request forwarded */);
 } else {
 vnc_desktop_resize_ext(vs, 3 /* Invalid screen layout */);
-- 
2.33.0.721.g106298f7f9




[PATCH v2 04/37] ui: generalize clipboard notifier

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Use a QemuClipboardNotify union type for extendable clipboard events.

Signed-off-by: Marc-André Lureau 
---
 include/ui/clipboard.h | 32 ++--
 ui/clipboard.c | 12 
 ui/gtk-clipboard.c | 20 
 ui/vdagent.c   | 27 ++-
 ui/vnc-clipboard.c | 18 ++
 ui/vnc.c   |  2 +-
 ui/cocoa.m | 17 +
 7 files changed, 100 insertions(+), 28 deletions(-)

diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h
index 6298986b15..d82cf31481 100644
--- a/include/ui/clipboard.h
+++ b/include/ui/clipboard.h
@@ -20,8 +20,10 @@
  */
 
 typedef enum QemuClipboardType QemuClipboardType;
+typedef enum QemuClipboardNotifyType QemuClipboardNotifyType;
 typedef enum QemuClipboardSelection QemuClipboardSelection;
 typedef struct QemuClipboardPeer QemuClipboardPeer;
+typedef struct QemuClipboardNotify QemuClipboardNotify;
 typedef struct QemuClipboardInfo QemuClipboardInfo;
 
 /**
@@ -55,18 +57,44 @@ enum QemuClipboardSelection {
  * struct QemuClipboardPeer
  *
  * @name: peer name.
- * @update: notifier for clipboard updates.
+ * @notifier: notifier for clipboard updates.
  * @request: callback for clipboard data requests.
  *
  * Clipboard peer description.
  */
 struct QemuClipboardPeer {
 const char *name;
-Notifier update;
+Notifier notifier;
 void (*request)(QemuClipboardInfo *info,
 QemuClipboardType type);
 };
 
+/**
+ * enum QemuClipboardNotifyType
+ *
+ * @QEMU_CLIPBOARD_UPDATE_INFO: clipboard info update
+ *
+ * Clipboard notify type.
+ */
+enum QemuClipboardNotifyType {
+QEMU_CLIPBOARD_UPDATE_INFO,
+};
+
+/**
+ * struct QemuClipboardNotify
+ *
+ * @type: the type of event.
+ * @info: a QemuClipboardInfo event.
+ *
+ * Clipboard notify data.
+ */
+struct QemuClipboardNotify {
+QemuClipboardNotifyType type;
+union {
+QemuClipboardInfo *info;
+};
+};
+
 /**
  * struct QemuClipboardInfo
  *
diff --git a/ui/clipboard.c b/ui/clipboard.c
index d7b008d62a..743b39edf4 100644
--- a/ui/clipboard.c
+++ b/ui/clipboard.c
@@ -8,7 +8,7 @@ static QemuClipboardInfo 
*cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
 
 void qemu_clipboard_peer_register(QemuClipboardPeer *peer)
 {
-notifier_list_add(_notifiers, >update);
+notifier_list_add(_notifiers, >notifier);
 }
 
 void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer)
@@ -18,8 +18,7 @@ void qemu_clipboard_peer_unregister(QemuClipboardPeer *peer)
 for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
 qemu_clipboard_peer_release(peer, i);
 }
-
-notifier_remove(>update);
+notifier_remove(>notifier);
 }
 
 bool qemu_clipboard_peer_owns(QemuClipboardPeer *peer,
@@ -44,10 +43,15 @@ void qemu_clipboard_peer_release(QemuClipboardPeer *peer,
 
 void qemu_clipboard_update(QemuClipboardInfo *info)
 {
+QemuClipboardNotify notify = {
+.type = QEMU_CLIPBOARD_UPDATE_INFO,
+.info = info,
+};
 g_autoptr(QemuClipboardInfo) old = NULL;
+
 assert(info->selection < QEMU_CLIPBOARD_SELECTION__COUNT);
 
-notifier_list_notify(_notifiers, info);
+notifier_list_notify(_notifiers, );
 
 old = cbinfo[info->selection];
 cbinfo[info->selection] = qemu_clipboard_info_ref(info);
diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c
index 35b7a2c228..44ff810234 100644
--- a/ui/gtk-clipboard.c
+++ b/ui/gtk-clipboard.c
@@ -74,10 +74,9 @@ static void gd_clipboard_clear(GtkClipboard *clipboard,
 gd->cbowner[s] = false;
 }
 
-static void gd_clipboard_notify(Notifier *notifier, void *data)
+static void gd_clipboard_update_info(GtkDisplayState *gd,
+ QemuClipboardInfo *info)
 {
-GtkDisplayState *gd = container_of(notifier, GtkDisplayState, 
cbpeer.update);
-QemuClipboardInfo *info = data;
 QemuClipboardSelection s = info->selection;
 bool self_update = info->owner == >cbpeer;
 
@@ -118,6 +117,19 @@ static void gd_clipboard_notify(Notifier *notifier, void 
*data)
  */
 }
 
+static void gd_clipboard_notify(Notifier *notifier, void *data)
+{
+GtkDisplayState *gd =
+container_of(notifier, GtkDisplayState, cbpeer.notifier);
+QemuClipboardNotify *notify = data;
+
+switch (notify->type) {
+case QEMU_CLIPBOARD_UPDATE_INFO:
+gd_clipboard_update_info(gd, notify->info);
+return;
+}
+}
+
 static void gd_clipboard_request(QemuClipboardInfo *info,
  QemuClipboardType type)
 {
@@ -172,7 +184,7 @@ static void gd_owner_change(GtkClipboard *clipboard,
 void gd_clipboard_init(GtkDisplayState *gd)
 {
 gd->cbpeer.name = "gtk";
-gd->cbpeer.update.notify = gd_clipboard_notify;
+gd->cbpeer.notifier.notify = gd_clipboard_notify;
 gd->cbpeer.request = gd_clipboard_request;
 qemu_clipboard_peer_register(>cbpeer);
 
diff --git a/ui/vdagent.c b/ui/vdagent.c
index 

[PATCH v2 01/37] build-sys: move Spice configure handling to meson

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Add meson feature options for Spice and Spice protocol, and move
detection logic out of configure.

Signed-off-by: Marc-André Lureau 
---
 configure   | 48 ++---
 meson.build | 27 -
 chardev/meson.build |  2 +-
 meson_options.txt   |  4 
 ui/meson.build  |  4 ++--
 5 files changed, 22 insertions(+), 63 deletions(-)

diff --git a/configure b/configure
index 877bf3d76a..375cde2b44 100755
--- a/configure
+++ b/configure
@@ -372,7 +372,7 @@ pie=""
 qom_cast_debug="yes"
 trace_backends="log"
 trace_file="trace"
-spice="$default_feature"
+spice="auto"
 spice_protocol="auto"
 rbd="auto"
 smartcard="auto"
@@ -3525,41 +3525,6 @@ EOF
   fi
 fi
 
-##
-# spice probe
-if test "$spice_protocol" != "no" ; then
-  spice_protocol_cflags=$($pkg_config --cflags spice-protocol 2>/dev/null)
-  if $pkg_config --atleast-version=0.12.3 spice-protocol; then
-spice_protocol="yes"
-  else
-if test "$spice_protocol" = "yes" ; then
-  feature_not_found "spice_protocol" \
-  "Install spice-protocol(>=0.12.3) devel"
-fi
-spice_protocol="no"
-  fi
-fi
-
-if test "$spice" != "no" ; then
-  cat > $TMPC << EOF
-#include 
-int main(void) { spice_server_new(); return 0; }
-EOF
-  spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
-  spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
-  if $pkg_config --atleast-version=0.12.5 spice-server && \
- test "$spice_protocol" = "yes" && \
- compile_prog "$spice_cflags" "$spice_libs" ; then
-spice="yes"
-  else
-if test "$spice" = "yes" ; then
-  feature_not_found "spice" \
-  "Install spice-server(>=0.12.5) devel"
-fi
-spice="no"
-  fi
-fi
-
 ##
 # check if we have VSS SDK headers for win
 
@@ -4659,16 +4624,6 @@ if test "$tcg" = "enabled" -a "$tcg_interpreter" = 
"true" ; then
   echo "CONFIG_TCG_INTERPRETER=y" >> $config_host_mak
 fi
 
-if test "$spice_protocol" = "yes" ; then
-  echo "CONFIG_SPICE_PROTOCOL=y" >> $config_host_mak
-  echo "SPICE_PROTOCOL_CFLAGS=$spice_protocol_cflags" >> $config_host_mak
-fi
-if test "$spice" = "yes" ; then
-  echo "CONFIG_SPICE=y" >> $config_host_mak
-  echo "SPICE_CFLAGS=$spice_cflags $spice_protocol_cflags" >> $config_host_mak
-  echo "SPICE_LIBS=$spice_libs" >> $config_host_mak
-fi
-
 if test "$opengl" = "yes" ; then
   echo "CONFIG_OPENGL=y" >> $config_host_mak
   echo "OPENGL_CFLAGS=$opengl_cflags" >> $config_host_mak
@@ -5202,6 +5157,7 @@ if test "$skip_meson" = no; then
 -Ddocs=$docs -Dsphinx_build=$sphinx_build -Dinstall_blobs=$blobs \
 -Dvhost_user_blk_server=$vhost_user_blk_server 
-Dmultiprocess=$multiprocess \
 -Dfuse=$fuse -Dfuse_lseek=$fuse_lseek 
-Dguest_agent_msi=$guest_agent_msi -Dbpf=$bpf\
+-Dspice=$spice -Dspice_protocol=$spice_protocol \
 $(if test "$default_feature" = no; then echo 
"-Dauto_features=disabled"; fi) \
-Dtcg_interpreter=$tcg_interpreter \
 $cross_arg \
diff --git a/meson.build b/meson.build
index 99a0a3e689..fe621413a4 100644
--- a/meson.build
+++ b/meson.build
@@ -442,17 +442,14 @@ jack = not_found
 if 'CONFIG_LIBJACK' in config_host
   jack = declare_dependency(link_args: config_host['JACK_LIBS'].split())
 endif
-spice = not_found
-spice_headers = not_found
-spice_protocol = not_found
-if 'CONFIG_SPICE' in config_host
-  spice = declare_dependency(compile_args: config_host['SPICE_CFLAGS'].split(),
- link_args: config_host['SPICE_LIBS'].split())
-  spice_headers = declare_dependency(compile_args: 
config_host['SPICE_CFLAGS'].split())
-endif
-if 'CONFIG_SPICE_PROTOCOL' in config_host
-  spice_protocol = declare_dependency(compile_args: 
config_host['SPICE_PROTOCOL_CFLAGS'].split())
-endif
+spice_protocol = dependency('spice-protocol', version: '>=0.12.3',
+required: get_option('spice_protocol'))
+spice = dependency('spice-server', version: '>=0.12.5',
+   required: get_option('spice'))
+if spice.found()
+  config_host += { 'CONFIG_SPICE': 'y' } # for audio/meson.build
+endif
+spice_headers = spice.partial_dependency(compile_args: true, includes: true)
 rt = cc.find_library('rt', required: false)
 libdl = not_found
 if 'CONFIG_PLUGIN' in config_host
@@ -1293,6 +1290,9 @@ config_host_data.set('CONFIG_ZSTD', zstd.found())
 config_host_data.set('CONFIG_FUSE', fuse.found())
 config_host_data.set('CONFIG_FUSE_LSEEK', fuse_lseek.found())
 config_host_data.set('CONFIG_X11', x11.found())
+config_host_data.set('CONFIG_SPICE_PROTOCOL', spice_protocol.found())
+config_host_data.set('CONFIG_SPICE', spice.found())
+config_host_data.set('CONFIG_X11', x11.found())
 config_host_data.set('CONFIG_CFI', get_option('cfi'))
 config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
 

[PATCH v2 03/37] ui/vdagent: replace #if 0 with protocol version check

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 ui/vdagent.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/ui/vdagent.c b/ui/vdagent.c
index 1f8fc77ee8..64e0017001 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -87,8 +87,10 @@ static const char *cap_name[] = {
 [VD_AGENT_CAP_MONITORS_CONFIG_POSITION]   = "monitors-config-position",
 [VD_AGENT_CAP_FILE_XFER_DISABLED] = "file-xfer-disabled",
 [VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS]  = 
"file-xfer-detailed-errors",
-#if 0
+#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 0)
 [VD_AGENT_CAP_GRAPHICS_DEVICE_INFO]   = "graphics-device-info",
+#endif
+#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1)
 [VD_AGENT_CAP_CLIPBOARD_NO_RELEASE_ON_REGRAB] = 
"clipboard-no-release-on-regrab",
 [VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL]  = "clipboard-grab-serial",
 #endif
@@ -110,7 +112,7 @@ static const char *msg_name[] = {
 [VD_AGENT_CLIENT_DISCONNECTED]   = "client-disconnected",
 [VD_AGENT_MAX_CLIPBOARD] = "max-clipboard",
 [VD_AGENT_AUDIO_VOLUME_SYNC] = "audio-volume-sync",
-#if 0
+#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 0)
 [VD_AGENT_GRAPHICS_DEVICE_INFO]  = "graphics-device-info",
 #endif
 };
@@ -128,7 +130,7 @@ static const char *type_name[] = {
 [VD_AGENT_CLIPBOARD_IMAGE_BMP]  = "bmp",
 [VD_AGENT_CLIPBOARD_IMAGE_TIFF] = "tiff",
 [VD_AGENT_CLIPBOARD_IMAGE_JPG]  = "jpg",
-#if 0
+#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 3)
 [VD_AGENT_CLIPBOARD_FILE_LIST]  = "files",
 #endif
 };
-- 
2.33.0.721.g106298f7f9




[PATCH v2 02/37] ui/vdagent: add CHECK_SPICE_PROTOCOL_VERSION

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Signed-off-by: Marc-André Lureau 
---
 meson.build  | 5 +
 ui/vdagent.c | 8 
 2 files changed, 13 insertions(+)

diff --git a/meson.build b/meson.build
index fe621413a4..e1cddf5139 100644
--- a/meson.build
+++ b/meson.build
@@ -1291,6 +1291,11 @@ config_host_data.set('CONFIG_FUSE', fuse.found())
 config_host_data.set('CONFIG_FUSE_LSEEK', fuse_lseek.found())
 config_host_data.set('CONFIG_X11', x11.found())
 config_host_data.set('CONFIG_SPICE_PROTOCOL', spice_protocol.found())
+if spice_protocol.found()
+config_host_data.set('CONFIG_SPICE_PROTOCOL_MAJOR', 
spice_protocol.version().split('.')[0])
+config_host_data.set('CONFIG_SPICE_PROTOCOL_MINOR', 
spice_protocol.version().split('.')[1])
+config_host_data.set('CONFIG_SPICE_PROTOCOL_MICRO', 
spice_protocol.version().split('.')[2])
+endif
 config_host_data.set('CONFIG_SPICE', spice.found())
 config_host_data.set('CONFIG_X11', x11.found())
 config_host_data.set('CONFIG_CFI', get_option('cfi'))
diff --git a/ui/vdagent.c b/ui/vdagent.c
index 19e8fbfc96..1f8fc77ee8 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -17,6 +17,14 @@
 
 #include "spice/vd_agent.h"
 
+#define CHECK_SPICE_PROTOCOL_VERSION(major, minor, micro) \
+(CONFIG_SPICE_PROTOCOL_MAJOR > (major) || \
+ (CONFIG_SPICE_PROTOCOL_MAJOR == (major) &&   \
+  CONFIG_SPICE_PROTOCOL_MINOR > (minor)) ||   \
+ (CONFIG_SPICE_PROTOCOL_MAJOR == (major) &&   \
+  CONFIG_SPICE_PROTOCOL_MINOR == (minor) &&   \
+  CONFIG_SPICE_PROTOCOL_MICRO >= (micro)))
+
 #define VDAGENT_BUFFER_LIMIT (1 * MiB)
 #define VDAGENT_MOUSE_DEFAULT true
 #define VDAGENT_CLIPBOARD_DEFAULT false
-- 
2.33.0.721.g106298f7f9




[PATCH v2 00/37] Add D-Bus display backend

2021-10-09 Thread marcandre . lureau
From: Marc-André Lureau 

Hi,

Both Spice and VNC are relatively complex and inefficient for local-only
display/console export.

The goal of this display backend is to export over D-Bus an interface close to
the QEMU internal APIs. Any -display or -audio backend should be possible to
implement externally that way. It will allow third-parties to maintain their own
backends (UI toolkits, servers etc), and eventually reduce the responsability on
QEMU.

D-Bus is the protocol of choice for the desktop, it has many convenient bindings
for various languages and tools. Data blob transfer is more efficient than QMP
too. Backends can come and go as needed: you can have several display opened
(say Boxes & virt-manager), while exporting the display over VNC for example
from a different process. It works best on Unix, but there is some Windows
support too (even Windows has some AF_UNIX nowadays, and the WSL2 situation may
change the future of QEMU on Windows anyway).

Using it only requires "-display dbus" on any reasonable Linux desktop with a
D-Bus session bus. Then you use can use busctl, d-feet or gdbus, ex:
$ gdbus introspect --session -r -d org.qemu -o /

See the different patches and documentation for further options. The p2p=on mode
should also allow users running bus-less (on MacOS for ex). We can also add TCP
socket if needed (although more work would be needed in this case to replace
the FD-passing with some extra TCP listening socket).

A WIP Rust/Gtk4 client and VNC server is: 
https://gitlab.com/marcandre.lureau/qemu-display/
(check README.md for details, then `cargo run` should connect to QEMU)

The Sphinx build support works best with "[PATCH 0/6] Some Sphinx improvements",
where module dependency tracking is improved.

I can resend the first set of preliminary patches after some feedback.

Thanks

v2:
 - rebased
 - drop for the vhost-user-gpu work for now
 - add documentation, including D-Bus Sphinx directive
 - add bus-less option (p2p=on)
 - add some basic tests for the Console/Keyboard interfaces
 - add clipboard sharing support
 - add chardev redirection support (allowing USB redirection, monitors,
   serials...)
 - register a VC handler to export default serial/monitors
 - probably a few bug fixes here and there too

Marc-André Lureau (37):
  build-sys: move Spice configure handling to meson
  ui/vdagent: add CHECK_SPICE_PROTOCOL_VERSION
  ui/vdagent: replace #if 0 with protocol version check
  ui: generalize clipboard notifier
  ui/vdagent: add serial capability support
  ui/clipboard: add qemu_clipboard_check_serial()
  ui/clipboard: add a clipboard reset serial event
  hw/display: report an error if virgl initialization failed
  virtio-gpu: use VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP
  ui: do not delay further remote resize
  ui: factor out qemu_console_set_display_gl_ctx()
  ui: associate GL context outside of display listener registration
  ui: make gl_block use a counter
  ui: add a gl-unblock warning timer
  ui: simplify gl unblock & flush
  ui: dispatch GL events to all listeners
  ui: split the GL context in a different object
  ui: move qemu_spice_fill_device_address to ui/util.c
  console: save current scanout details
  scripts: teach modinfo to skip non-C sources
  docs/sphinx: add sphinx modules to include D-Bus documentation
  backends: move dbus-vmstate1.xml to backends/
  docs: move D-Bus VMState documentation to source XML
  docs: add dbus-display documentation
  build-sys: set glib dependency version
  ui: add a D-Bus display backend
  ui/dbus: add p2p=on/off option
  tests/qtests: add qtest_qmp_add_client()
  tests: start dbus-display-test
  audio: add "dbus" audio backend
  ui/dbus: add clipboard interface
  chardev: teach socket to accept no addresses
  chardev: make socket derivable
  option: add g_auto for QemuOpts
  ui/dbus: add chardev backend & interface
  ui/dbus: register D-Bus VC handler
  MAINTAINERS: update D-Bus section

 docs/conf.py|   8 +
 docs/interop/dbus-display.rst   |  31 ++
 docs/interop/dbus-vmstate.rst   |  52 +--
 docs/interop/dbus.rst   |   2 +
 docs/interop/index.rst  |   1 +
 docs/sphinx/dbusdoc.py  | 166 +++
 docs/sphinx/dbusdomain.py   | 406 +
 docs/sphinx/dbusparser.py   | 373 
 docs/sphinx/fakedbusdoc.py  |  25 ++
 configure   |  49 +-
 meson.build |  46 +-
 qapi/audio.json |   3 +-
 qapi/char.json  |  27 ++
 qapi/misc.json  |   4 +-
 qapi/ui.json|  34 +-
 audio/audio_int.h   |   7 +
 audio/audio_template.h  |   2 +
 include/chardev/char-socket.h   |  86 
 include/qemu/cutils.h   |   5 +
 include/qemu/dbus.h |  24 +
 include/qemu/option.h   |   2 +
 include/ui/clipboard.h  |  55 ++-
 include/ui/console.h|  70 ++-
 include/ui/dbus-display.h   |  17 +
 include/ui/dbus-module.h

Re: [PATCH v2 11/15] bsd-user: Add stop_all_tasks

2021-10-09 Thread Richard Henderson

On 10/8/21 4:15 PM, Warner Losh wrote:

Similar to the same function in linux-user: this stops all the current tasks.

Signed-off-by: Stacey Son
Signed-off-by: Warner Losh
---
  bsd-user/main.c | 9 +
  bsd-user/qemu.h | 1 +
  2 files changed, 10 insertions(+)


Reviewed-by: Richard Henderson 

r~



Re: [PATCH v2 15/15] bsd-user/signal: Create a dummy signal queueing function

2021-10-09 Thread Richard Henderson

On 10/8/21 4:15 PM, Warner Losh wrote:

Create dummy signal queueing function so we can start to integrate other
architectures (at the cost of signals remaining broken) to tame the
dependency graph a bit and to bring in signals in a more controlled
fashion. Log unimplemented events to it in the mean time.

Signed-off-by: Warner Losh
---
  bsd-user/qemu.h   |  2 +-
  bsd-user/signal.c | 11 ++-
  2 files changed, 11 insertions(+), 2 deletions(-)


Reviewed-by: Richard Henderson 

r~



Re: [PATCH v3 7/9] bsd-user/mmap.c: Don't mmap fd == -1 independently from MAP_ANON flag

2021-10-09 Thread Richard Henderson

On 10/8/21 2:23 PM, Warner Losh wrote:

From: Guy Yur

Switch checks for !(flags & MAP_ANONYMOUS) with checks for fd != -1.
MAP_STACK and MAP_GUARD both require fd == -1 and don't require mapping
the fd either. Add analysis from Guy Yur detailing the different cases
for MAP_GUARD and MAP_STACK.

Signed-off-by: Guy Yur
[ partially merged before, finishing the job and documenting origin]
Signed-off-by: Warner Losh
---
  bsd-user/mmap.c | 30 +-
  1 file changed, 25 insertions(+), 5 deletions(-)


Reviewed-by: Richard Henderson 

r~



Re: [PATCH] Trim some trailing space from human-readable output

2021-10-09 Thread Richard Henderson

On 10/9/21 8:24 AM, Markus Armbruster wrote:

I noticed -cpu help printing enough trailing spaces to make the output
at least 84 characters wide.  Looks ugly unless the terminal is wider.
Ugly or not, trailing spaces are stupid.

The culprit is this line in x86_cpu_list_entry():

 qemu_printf("x86 %-20s  %-58s\n", name, desc);

This prints a string with minimum field left-justified right before a
newline.  Change it to

 qemu_printf("x86 %-20s  %s\n", name, desc);

which avoids the trailing spaces and is simpler to boot.

A search for the pattern with "git-grep -E '%-[0-9]+s\\n'" found a few
more instances.  Change them similarly.

Signed-off-by: Markus Armbruster
---
  monitor/hmp-cmds.c | 2 +-
  target/i386/cpu-dump.c | 4 ++--
  target/i386/cpu.c  | 2 +-
  target/ppc/cpu_init.c  | 2 +-
  target/s390x/cpu_models.c  | 4 ++--
  target/xtensa/mmu_helper.c | 2 +-
  6 files changed, 8 insertions(+), 8 deletions(-)


Reviewed-by: Richard Henderson 

r~



Re: [PATCH v3 8/9] bsd-user/mmap.c: Implement MAP_EXCL, required by jemalloc in head

2021-10-09 Thread Richard Henderson

On 10/8/21 2:23 PM, Warner Losh wrote:

From: Kyle Evans

jemalloc requires a working MAP_EXCL. Ensure that no page is double
mapped when specified. In addition, use guest_range_valid_untagged to
test for valid ranges of pages rather than an incomplete inlined version
of the test that might be wrong.

Signed-off-by: Kyle Evans
Signed-off-by: Warner Losh
---
  bsd-user/mmap.c | 12 
  1 file changed, 8 insertions(+), 4 deletions(-)


Reviewed-by: Richard Henderson 

r~



Re: [PATCH v3 6/9] bsd-user/mmap.c: Convert to qemu_log logging for mmap debugging

2021-10-09 Thread Richard Henderson

On 10/8/21 2:23 PM, Warner Losh wrote:

Convert DEBUG_MMAP to qemu_log CPU_LOG_PAGE.

Signed-off-by: Warner Losh
---
  bsd-user/mmap.c | 53 +
  1 file changed, 23 insertions(+), 30 deletions(-)


Reviewed-by: Richard Henderson 

r~



[PATCH] Trim some trailing space from human-readable output

2021-10-09 Thread Markus Armbruster
I noticed -cpu help printing enough trailing spaces to make the output
at least 84 characters wide.  Looks ugly unless the terminal is wider.
Ugly or not, trailing spaces are stupid.

The culprit is this line in x86_cpu_list_entry():

qemu_printf("x86 %-20s  %-58s\n", name, desc);

This prints a string with minimum field left-justified right before a
newline.  Change it to

qemu_printf("x86 %-20s  %s\n", name, desc);

which avoids the trailing spaces and is simpler to boot.

A search for the pattern with "git-grep -E '%-[0-9]+s\\n'" found a few
more instances.  Change them similarly.

Signed-off-by: Markus Armbruster 
---
 monitor/hmp-cmds.c | 2 +-
 target/i386/cpu-dump.c | 4 ++--
 target/i386/cpu.c  | 2 +-
 target/ppc/cpu_init.c  | 2 +-
 target/s390x/cpu_models.c  | 4 ++--
 target/xtensa/mmu_helper.c | 2 +-
 6 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index bcaa41350e..9e45a138a5 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -1945,7 +1945,7 @@ void hmp_rocker_ports(Monitor *mon, const QDict *qdict)
 monitor_printf(mon, "  port  linkduplex neg?\n");
 
 for (port = list; port; port = port->next) {
-monitor_printf(mon, "%10s  %-4s   %-3s  %2s  %-3s\n",
+monitor_printf(mon, "%10s  %-4s   %-3s  %2s  %s\n",
port->value->name,
port->value->enabled ? port->value->link_up ?
"up" : "down" : "!ena",
diff --git a/target/i386/cpu-dump.c b/target/i386/cpu-dump.c
index 02b635a52c..08ac957e99 100644
--- a/target/i386/cpu-dump.c
+++ b/target/i386/cpu-dump.c
@@ -464,13 +464,13 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
 #ifdef TARGET_X86_64
 if (env->hflags & HF_CS64_MASK) {
-qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
+qemu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%s\n",
  env->cc_src, env->cc_dst,
  cc_op_name);
 } else
 #endif
 {
-qemu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
+qemu_fprintf(f, "CCS=%08x CCD=%08x CCO=%s\n",
  (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
  cc_op_name);
 }
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index a7b1b6aa93..8d2c0ded10 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -4876,7 +4876,7 @@ static void x86_cpu_list_entry(gpointer data, gpointer 
user_data)
 desc = g_strdup_printf("%s", model_id);
 }
 
-qemu_printf("x86 %-20s  %-58s\n", name, desc);
+qemu_printf("x86 %-20s  %s\n", name, desc);
 }
 
 /* list available CPU models and flags */
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 6aad01d1d3..8ab81dd1ed 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -8734,7 +8734,7 @@ void ppc_cpu_list(void)
 
 #ifdef CONFIG_KVM
 qemu_printf("\n");
-qemu_printf("PowerPC %-16s\n", "host");
+qemu_printf("PowerPC %s\n", "host");
 #endif
 }
 
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 4e4598cc77..11e06cc51f 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -398,14 +398,14 @@ void s390_cpu_list(void)
 for (feat = 0; feat < S390_FEAT_MAX; feat++) {
 const S390FeatDef *def = s390_feat_def(feat);
 
-qemu_printf("%-20s %-50s\n", def->name, def->desc);
+qemu_printf("%-20s %s\n", def->name, def->desc);
 }
 
 qemu_printf("\nRecognized feature groups:\n");
 for (group = 0; group < S390_FEAT_GROUP_MAX; group++) {
 const S390FeatGroupDef *def = s390_feat_group_def(group);
 
-qemu_printf("%-20s %-50s\n", def->name, def->desc);
+qemu_printf("%-20s %s\n", def->name, def->desc);
 }
 }
 
diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c
index b01ff9399a..57e319a1af 100644
--- a/target/xtensa/mmu_helper.c
+++ b/target/xtensa/mmu_helper.c
@@ -1098,7 +1098,7 @@ static void dump_tlb(CPUXtensaState *env, bool dtlb)
 qemu_printf("\tVaddr   Paddr   ASID  Attr RWX 
Cache\n"
 "\t--  --     --- 
---\n");
 }
-qemu_printf("\t0x%08x  0x%08x  0x%02x  0x%02x %c%c%c %-7s\n",
+qemu_printf("\t0x%08x  0x%08x  0x%02x  0x%02x %c%c%c %s\n",
 entry->vaddr,
 entry->paddr,
 entry->asid,
-- 
2.31.1




Re: [PATCH v2 01/15] meson: *-user: only descend into *-user when configured

2021-10-09 Thread Warner Losh
(looks like Paolo's email bounced, so try again with cut and paste)

On Fri, Oct 8, 2021 at 5:15 PM Warner Losh  wrote:

> To increase flexibility, only descend into *-user when that is
> configured. This allows *-user to selectively include directories based
> on the host OS which may not exist on all hosts. Adopt Paolo's
> suggestion of checking the configuration in the directories that know
> about the configuration.
>
> Message-Id: <20210926220103.1721355-2-f4...@amsat.org>
> Message-Id: <20210926220103.1721355-3-f4...@amsat.org>
> Signed-off-by: Philippe Mathieu-Daudé 
> Signed-off-by: Warner Losh 
> Acked-by: Paolo Bonzini 
>
> Sponsored by:   Netflix
> ---
>  bsd-user/meson.build   | 4 
>  linux-user/meson.build | 4 
>  meson.build| 3 +--
>  3 files changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/bsd-user/meson.build b/bsd-user/meson.build
> index 0369549340..243fb78930 100644
> --- a/bsd-user/meson.build
> +++ b/bsd-user/meson.build
> @@ -1,3 +1,7 @@
> +if not config_target.has_key('CONFIG_BSD_USER')
> +   subdir_done()
> +endif
> +
>  bsd_user_ss.add(files(
>'bsdload.c',
>'elfload.c',
> diff --git a/linux-user/meson.build b/linux-user/meson.build
> index 9549f81682..602255a3d6 100644
> --- a/linux-user/meson.build
> +++ b/linux-user/meson.build
> @@ -1,3 +1,7 @@
> +if not config_target.has_key('CONFIG_LINUX_USER')
> +   subdir_done()
> +endif
> +
>  linux_user_ss.add(files(
>'elfload.c',
>'exit.c',
> diff --git a/meson.build b/meson.build
> index 99a0a3e689..1f2da5f7d9 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -2303,10 +2303,9 @@ subdir('ebpf')
>
>  common_ss.add(libbpf)
>
> -bsd_user_ss.add(files('gdbstub.c'))
>  specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss)
>
> -linux_user_ss.add(files('gdbstub.c', 'thunk.c'))
> +linux_user_ss.add(files('thunk.c'))
>  specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss)
>
>  # needed for fuzzing binaries
> --
> 2.32.0
>
>


Re: [PATCH] qapi: Make some ObjectTypes depend on the build settings

2021-10-09 Thread Markus Armbruster
Paolo Bonzini  writes:

> On 08/10/21 14:01, Markus Armbruster wrote:
>> Paolo, do you have something for QOM queued up already?  If not, I'm
>> happy to take this through my tree.
>> 
>
> I don't but I have enough stuff that I'll be sending a pull request
> shortly.  So, queued, and while at it I also made memory-backend-epc 
> depend on CONFIG_LINUX (more strictly it depends on CONFIG_SGX, which
> depends on CONFIG_KVM, which depends on CONFIG_LINUX; but the other
> two are target-dependent so we have to do with CONFIG_LINUX).

Thanks!

Could you throw in this one?

Subject: [PATCH] monitor: Tidy up find_device_state()
Date: Thu, 16 Sep 2021 13:17:07 +0200
Message-Id: <20210916111707.84999-1-arm...@redhat.com>




[PATCH v2 4/5] qapi: Implement deprecated-input={reject, crash} for enum values

2021-10-09 Thread Markus Armbruster
This copies the code implementing the policy from qapi/qmp-dispatch.c
to qapi/qobject-input-visitor.c.  Tolerable, but if we acquire more
copes, we should look into factoring them out.

Signed-off-by: Markus Armbruster 
---
 docs/devel/qapi-code-gen.rst |  6 --
 qapi/compat.json |  3 ++-
 include/qapi/util.h  |  6 +-
 qapi/qapi-visit-core.c   | 18 +++---
 scripts/qapi/types.py| 17 -
 5 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst
index 00334e9fb8..006a6f4a9a 100644
--- a/docs/devel/qapi-code-gen.rst
+++ b/docs/devel/qapi-code-gen.rst
@@ -708,8 +708,10 @@ QEMU shows a certain behaviour.
 Special features
 
 
-Feature "deprecated" marks a command, event, or struct member as
-deprecated.  It is not supported elsewhere so far.
+Feature "deprecated" marks a command, event, struct or enum member as
+deprecated.  It is not supported elsewhere so far.  Interfaces so
+marked may be withdrawn in future releases in accordance with QEMU's
+deprecation policy.
 
 
 Naming rules and reserved names
diff --git a/qapi/compat.json b/qapi/compat.json
index 1d2b76f00c..74a8493d3d 100644
--- a/qapi/compat.json
+++ b/qapi/compat.json
@@ -42,7 +42,8 @@
 # with feature 'deprecated'.  We may want to extend it to cover
 # semantic aspects, CLI, and experimental features.
 #
-# Limitation: not implemented for deprecated enumeration values.
+# Limitation: deprecated-output policy @hide is not implemented for
+# enumeration values.  They behave the same as with policy @accept.
 #
 # @deprecated-input: how to handle deprecated input (default 'accept')
 # @deprecated-output: how to handle deprecated output (default 'accept')
diff --git a/include/qapi/util.h b/include/qapi/util.h
index d7bfb30e25..257c600f99 100644
--- a/include/qapi/util.h
+++ b/include/qapi/util.h
@@ -11,9 +11,13 @@
 #ifndef QAPI_UTIL_H
 #define QAPI_UTIL_H
 
+/* QEnumLookup flags */
+#define QAPI_ENUM_DEPRECATED 1
+
 typedef struct QEnumLookup {
 const char *const *array;
-int size;
+const unsigned char *const flags;
+const int size;
 } QEnumLookup;
 
 const char *qapi_enum_lookup(const QEnumLookup *lookup, int val);
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 066f77a26d..49136ae88e 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -393,7 +393,7 @@ static bool input_type_enum(Visitor *v, const char *name, 
int *obj,
 const QEnumLookup *lookup, Error **errp)
 {
 int64_t value;
-char *enum_str;
+g_autofree char *enum_str = NULL;
 
 if (!visit_type_str(v, name, _str, errp)) {
 return false;
@@ -402,11 +402,23 @@ static bool input_type_enum(Visitor *v, const char *name, 
int *obj,
 value = qapi_enum_parse(lookup, enum_str, -1, NULL);
 if (value < 0) {
 error_setg(errp, QERR_INVALID_PARAMETER, enum_str);
-g_free(enum_str);
 return false;
 }
 
-g_free(enum_str);
+if (lookup->flags && (lookup->flags[value] & QAPI_ENUM_DEPRECATED)) {
+switch (v->compat_policy.deprecated_input) {
+case COMPAT_POLICY_INPUT_ACCEPT:
+break;
+case COMPAT_POLICY_INPUT_REJECT:
+error_setg(errp, "Deprecated value '%s' disabled by policy",
+   enum_str);
+return false;
+case COMPAT_POLICY_INPUT_CRASH:
+default:
+abort();
+}
+}
+
 *obj = value;
 return true;
 }
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index 831294fe42..ab2441adc9 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -38,6 +38,8 @@
 def gen_enum_lookup(name: str,
 members: List[QAPISchemaEnumMember],
 prefix: Optional[str] = None) -> str:
+max_index = c_enum_const(name, '_MAX', prefix)
+flags = ''
 ret = mcgen('''
 
 const QEnumLookup %(c_name)s_lookup = {
@@ -52,13 +54,26 @@ def gen_enum_lookup(name: str,
 ''',
  index=index, name=memb.name)
 ret += memb.ifcond.gen_endif()
+if 'deprecated' in (f.name for f in memb.features):
+flags += mcgen('''
+[%(index)s] = QAPI_ENUM_DEPRECATED,
+''',
+   index=index)
+
+if flags:
+ret += mcgen('''
+},
+.flags = (const unsigned char[%(max_index)s]) {
+''',
+ max_index=max_index)
+ret += flags
 
 ret += mcgen('''
 },
 .size = %(max_index)s
 };
 ''',
- max_index=c_enum_const(name, '_MAX', prefix))
+ max_index=max_index)
 return ret
 
 
-- 
2.31.1




[PATCH RFC v2 5/5] block: Deprecate transaction type drive-backup

2021-10-09 Thread Markus Armbruster
Several moons ago, Vladimir posted

Subject: [PATCH v2 3/3] qapi: deprecate drive-backup
Date: Wed,  5 May 2021 16:58:03 +0300
Message-Id: <20210505135803.67896-4-vsement...@virtuozzo.com>
https://lists.gnu.org/archive/html/qemu-devel/2021-05/msg01394.html

with this

TODO: We also need to deprecate drive-backup transaction action..
But union members in QAPI doesn't support 'deprecated' feature. I tried
to dig a bit, but failed :/ Markus, could you please help with it? At
least by advice?

This is one way to resolve it.  Sorry it took so long.

John explored another way, namely adding feature flags to union
branches.  Could also be useful, say to add different features to
branches in multiple unions sharing the same tag enum.

Signed-off-by: Markus Armbruster 
---
 qapi/transaction.json | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/qapi/transaction.json b/qapi/transaction.json
index d175b5f863..0564a893b3 100644
--- a/qapi/transaction.json
+++ b/qapi/transaction.json
@@ -54,6 +54,9 @@
 # @blockdev-snapshot-sync: since 1.1
 # @drive-backup: Since 1.6
 #
+# Features:
+# @deprecated: Member @drive-backup is deprecated.  Use FIXME instead.
+#
 # Since: 1.1
 ##
 { 'enum': 'TransactionActionKind',
@@ -62,7 +65,7 @@
 'block-dirty-bitmap-disable', 'block-dirty-bitmap-merge',
 'blockdev-backup', 'blockdev-snapshot',
 'blockdev-snapshot-internal-sync', 'blockdev-snapshot-sync',
-'drive-backup' ] }
+{ 'name': 'drive-backup', 'features': [ 'deprecated' ] } ] }
 
 ##
 # @AbortWrapper:
-- 
2.31.1




[PATCH v2 3/5] qapi: Move compat policy from QObject to generic visitor

2021-10-09 Thread Markus Armbruster
The next commit needs to access compat policy from the generic visitor
core.  Move it there from qobject input and output visitor.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 include/qapi/qobject-input-visitor.h  |  4 
 include/qapi/qobject-output-visitor.h |  4 
 include/qapi/visitor-impl.h   |  3 +++
 include/qapi/visitor.h|  9 +
 qapi/qapi-visit-core.c|  9 +
 qapi/qmp-dispatch.c   |  4 ++--
 qapi/qobject-input-visitor.c  | 14 +-
 qapi/qobject-output-visitor.c | 14 +-
 8 files changed, 25 insertions(+), 36 deletions(-)

diff --git a/include/qapi/qobject-input-visitor.h 
b/include/qapi/qobject-input-visitor.h
index 8d69388810..95985e25e5 100644
--- a/include/qapi/qobject-input-visitor.h
+++ b/include/qapi/qobject-input-visitor.h
@@ -15,7 +15,6 @@
 #ifndef QOBJECT_INPUT_VISITOR_H
 #define QOBJECT_INPUT_VISITOR_H
 
-#include "qapi/qapi-types-compat.h"
 #include "qapi/visitor.h"
 
 typedef struct QObjectInputVisitor QObjectInputVisitor;
@@ -59,9 +58,6 @@ typedef struct QObjectInputVisitor QObjectInputVisitor;
  */
 Visitor *qobject_input_visitor_new(QObject *obj);
 
-void qobject_input_visitor_set_policy(Visitor *v,
-  CompatPolicyInput deprecated);
-
 /*
  * Create a QObject input visitor for @obj for use with keyval_parse()
  *
diff --git a/include/qapi/qobject-output-visitor.h 
b/include/qapi/qobject-output-visitor.h
index f2a2f92a00..2b1726baf5 100644
--- a/include/qapi/qobject-output-visitor.h
+++ b/include/qapi/qobject-output-visitor.h
@@ -15,7 +15,6 @@
 #define QOBJECT_OUTPUT_VISITOR_H
 
 #include "qapi/visitor.h"
-#include "qapi/qapi-types-compat.h"
 
 typedef struct QObjectOutputVisitor QObjectOutputVisitor;
 
@@ -54,7 +53,4 @@ typedef struct QObjectOutputVisitor QObjectOutputVisitor;
  */
 Visitor *qobject_output_visitor_new(QObject **result);
 
-void qobject_output_visitor_set_policy(Visitor *v,
-   CompatPolicyOutput deprecated);
-
 #endif
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index 3b950f6e3d..72b6537bef 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -122,6 +122,9 @@ struct Visitor
 /* Must be set */
 VisitorType type;
 
+/* Optional */
+struct CompatPolicy compat_policy;
+
 /* Must be set for output visitors, optional otherwise. */
 void (*complete)(Visitor *v, void *opaque);
 
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index b3c9ef7a81..dcb96018a9 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -16,6 +16,7 @@
 #define QAPI_VISITOR_H
 
 #include "qapi/qapi-builtin-types.h"
+#include "qapi/qapi-types-compat.h"
 
 /*
  * The QAPI schema defines both a set of C data types, and a QMP wire
@@ -477,6 +478,14 @@ bool visit_deprecated_accept(Visitor *v, const char *name, 
Error **errp);
  */
 bool visit_deprecated(Visitor *v, const char *name);
 
+/*
+ * Set policy for handling deprecated management interfaces.
+ *
+ * Intended use: call visit_set_policy(v, _policy) when
+ * visiting management interface input or output.
+ */
+void visit_set_policy(Visitor *v, CompatPolicy *policy);
+
 /*
  * Visit an enum value.
  *
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index a641adec51..066f77a26d 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -19,6 +19,10 @@
 #include "qapi/visitor-impl.h"
 #include "trace.h"
 
+/* Zero-initialization must result in default policy */
+QEMU_BUILD_BUG_ON(COMPAT_POLICY_INPUT_ACCEPT || COMPAT_POLICY_OUTPUT_ACCEPT);
+
+
 void visit_complete(Visitor *v, void *opaque)
 {
 assert(v->type != VISITOR_OUTPUT || v->complete);
@@ -153,6 +157,11 @@ bool visit_deprecated(Visitor *v, const char *name)
 return true;
 }
 
+void visit_set_policy(Visitor *v, CompatPolicy *policy)
+{
+v->compat_policy = *policy;
+}
+
 bool visit_is_input(Visitor *v)
 {
 return v->type == VISITOR_INPUT;
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 59600210ce..7e943a0af5 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -32,7 +32,7 @@ Visitor *qobject_input_visitor_new_qmp(QObject *obj)
 {
 Visitor *v = qobject_input_visitor_new(obj);
 
-qobject_input_visitor_set_policy(v, compat_policy.deprecated_input);
+visit_set_policy(v, _policy);
 return v;
 }
 
@@ -40,7 +40,7 @@ Visitor *qobject_output_visitor_new_qmp(QObject **result)
 {
 Visitor *v = qobject_output_visitor_new(result);
 
-qobject_output_visitor_set_policy(v, compat_policy.deprecated_output);
+visit_set_policy(v, _policy);
 return v;
 }
 
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index 04b790412e..71b24a4429 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -14,7 +14,6 @@
 
 #include "qemu/osdep.h"
 #include 
-#include "qapi/compat-policy.h"
 #include 

[PATCH v2 2/5] qapi: Add feature flags to enum members

2021-10-09 Thread Markus Armbruster
This is quite similar to commit 84ab008687 "qapi: Add feature flags to
struct members", only for enums instead of structs.

Special feature flag 'deprecated' is silently ignored there.  This is
okay only because it will be implemented shortly.

Signed-off-by: Markus Armbruster 
Reviewed-by: Eric Blake 
---
 docs/devel/qapi-code-gen.rst  |  4 +++-
 qapi/compat.json  |  2 ++
 qapi/introspect.json  |  5 -
 scripts/qapi/expr.py  |  3 ++-
 scripts/qapi/introspect.py|  5 +++--
 scripts/qapi/schema.py| 22 +--
 tests/qapi-schema/doc-good.json   |  5 -
 tests/qapi-schema/doc-good.out|  3 +++
 tests/qapi-schema/doc-good.txt|  3 +++
 .../qapi-schema/enum-dict-member-unknown.err  |  2 +-
 tests/qapi-schema/qapi-schema-test.json   |  3 ++-
 tests/qapi-schema/qapi-schema-test.out|  1 +
 tests/qapi-schema/test-qapi.py|  1 +
 13 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst
index b2569de486..00334e9fb8 100644
--- a/docs/devel/qapi-code-gen.rst
+++ b/docs/devel/qapi-code-gen.rst
@@ -200,7 +200,9 @@ Syntax::
  '*if': COND,
  '*features': FEATURES }
 ENUM-VALUE = STRING
-   | { 'name': STRING, '*if': COND }
+   | { 'name': STRING,
+   '*if': COND,
+   '*features': FEATURES }
 
 Member 'enum' names the enum type.
 
diff --git a/qapi/compat.json b/qapi/compat.json
index ae3afc22df..1d2b76f00c 100644
--- a/qapi/compat.json
+++ b/qapi/compat.json
@@ -42,6 +42,8 @@
 # with feature 'deprecated'.  We may want to extend it to cover
 # semantic aspects, CLI, and experimental features.
 #
+# Limitation: not implemented for deprecated enumeration values.
+#
 # @deprecated-input: how to handle deprecated input (default 'accept')
 # @deprecated-output: how to handle deprecated output (default 'accept')
 #
diff --git a/qapi/introspect.json b/qapi/introspect.json
index f806bd7281..4a3b76464e 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -163,10 +163,13 @@
 #
 # @name: the member's name, as defined in the QAPI schema.
 #
+# @features: names of features associated with the member, in no
+#particular order.
+#
 # Since: 6.2
 ##
 { 'struct': 'SchemaInfoEnumMember',
-  'data': { 'name': 'str' } }
+  'data': { 'name': 'str', '*features': [ 'str' ] } }
 
 ##
 # @SchemaInfoArray:
diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py
index 819ea6ad97..3cb389e875 100644
--- a/scripts/qapi/expr.py
+++ b/scripts/qapi/expr.py
@@ -472,7 +472,7 @@ def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> 
None:
   for m in members]
 for member in members:
 source = "'data' member"
-check_keys(member, info, source, ['name'], ['if'])
+check_keys(member, info, source, ['name'], ['if', 'features'])
 member_name = member['name']
 check_name_is_str(member_name, info, source)
 source = "%s '%s'" % (source, member_name)
@@ -483,6 +483,7 @@ def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> 
None:
  permit_upper=permissive,
  permit_underscore=permissive)
 check_if(member, info, source)
+check_features(member.get('features'), info)
 
 
 def check_struct(expr: _JSONObject, info: QAPISourceInfo) -> None:
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index 6334546363..67c7d89aae 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -275,12 +275,13 @@ def _gen_tree(self, name: str, mtype: str, obj: Dict[str, 
object],
 obj['features'] = self._gen_features(features)
 self._trees.append(Annotated(obj, ifcond, comment))
 
-@staticmethod
-def _gen_enum_member(member: QAPISchemaEnumMember
+def _gen_enum_member(self, member: QAPISchemaEnumMember
  ) -> Annotated[SchemaInfoEnumMember]:
 obj: SchemaInfoEnumMember = {
 'name': member.name,
 }
+if member.features:
+obj['features'] = self._gen_features(member.features)
 return Annotated(obj, member.ifcond)
 
 def _gen_object_member(self, member: QAPISchemaObjectTypeMember
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 004d7095ff..6d5f46509a 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -708,6 +708,19 @@ def describe(self, info):
 class QAPISchemaEnumMember(QAPISchemaMember):
 role = 'value'
 
+def __init__(self, name, info, ifcond=None, features=None):
+super().__init__(name, info, ifcond)
+for f in features or []:
+assert isinstance(f, QAPISchemaFeature)
+f.set_defined_in(name)
+self.features = features or []
+
+

[PATCH v2 1/5] qapi: Enable enum member introspection to show more than name

2021-10-09 Thread Markus Armbruster
The next commit will add feature flags to enum members.  There's a
problem, though: query-qmp-schema shows an enum type's members as an
array of member names (SchemaInfoEnum member @values).  If it showed
an array of objects with a name member, we could simply add more
members to these objects.  Since it's just strings, we can't.

I can see three ways to correct this design mistake:

1. Do it the way we should have done it, plus compatibility goo.

   We want a ['SchemaInfoEnumMember'] member in SchemaInfoEnum.  Since
   changing @values would be a compatibility break, add a new member
   @members instead.

   @values is now redundant.  In my testing, output of
   qemu-system-x86_64's query-qmp-schema grows by 11% (18.5KiB).

   We can deprecate @values now and drop it later.  This will break
   outmoded clients.  Well-behaved clients such as libvirt are
   expected to break cleanly.

2. Like 1, but omit "boring" elements of @member, and empty @member.

   @values does not become redundant.  @members augments it.  Somewhat
   cumbersome, but output of query-qmp-schema grows only as we make
   enum members non-boring.

   There is nothing to deprecate here.

3. Versioned query-qmp-schema.

   query-qmp-schema provides either @values or @members.  The QMP
   client can select which version it wants.  There is no redundant
   output.

   We can deprecate old versions and eventually drop them.  This will
   break outmoded clients.  Breaking cleanly is easier than for 1.

   While 1 and 2 operate within the common rules for compatible
   evolution apply (section "Compatibility considerations" in
   docs/devel/qapi-code-gen.rst), 3 bypasses them.  Attractive when
   operating within the rules is just too awkward.  Not the case here.

This commit implements 1.  Libvirt developers prefer it.

Signed-off-by: Markus Armbruster 
---
 qapi/introspect.json   | 21 +++--
 scripts/qapi/introspect.py | 18 ++
 2 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/qapi/introspect.json b/qapi/introspect.json
index 39bd303778..f806bd7281 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -142,14 +142,31 @@
 #
 # Additional SchemaInfo members for meta-type 'enum'.
 #
-# @values: the enumeration type's values, in no particular order.
+# @members: the enum type's members, in no particular order
+#   (since 6.2).
+#
+# @values: the enumeration type's member names, in no particular order.
+#  Redundant with @members.  Just for backward compatibility.
 #
 # Values of this type are JSON string on the wire.
 #
 # Since: 2.5
 ##
 { 'struct': 'SchemaInfoEnum',
-  'data': { 'values': ['str'] } }
+  'data': { 'members': [ 'SchemaInfoEnumMember' ],
+'values': ['str'] } }
+
+##
+# @SchemaInfoEnumMember:
+#
+# An object member.
+#
+# @name: the member's name, as defined in the QAPI schema.
+#
+# Since: 6.2
+##
+{ 'struct': 'SchemaInfoEnumMember',
+  'data': { 'name': 'str' } }
 
 ##
 # @SchemaInfoArray:
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index 4c079ee627..6334546363 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -68,6 +68,7 @@
 # TypedDict constructs, so they are broadly typed here as simple
 # Python Dicts.
 SchemaInfo = Dict[str, object]
+SchemaInfoEnumMember = Dict[str, object]
 SchemaInfoObject = Dict[str, object]
 SchemaInfoObjectVariant = Dict[str, object]
 SchemaInfoObjectMember = Dict[str, object]
@@ -274,8 +275,16 @@ def _gen_tree(self, name: str, mtype: str, obj: Dict[str, 
object],
 obj['features'] = self._gen_features(features)
 self._trees.append(Annotated(obj, ifcond, comment))
 
-def _gen_member(self, member: QAPISchemaObjectTypeMember
-) -> Annotated[SchemaInfoObjectMember]:
+@staticmethod
+def _gen_enum_member(member: QAPISchemaEnumMember
+ ) -> Annotated[SchemaInfoEnumMember]:
+obj: SchemaInfoEnumMember = {
+'name': member.name,
+}
+return Annotated(obj, member.ifcond)
+
+def _gen_object_member(self, member: QAPISchemaObjectTypeMember
+   ) -> Annotated[SchemaInfoObjectMember]:
 obj: SchemaInfoObjectMember = {
 'name': member.name,
 'type': self._use_type(member.type)
@@ -305,7 +314,8 @@ def visit_enum_type(self, name: str, info: 
Optional[QAPISourceInfo],
 prefix: Optional[str]) -> None:
 self._gen_tree(
 name, 'enum',
-{'values': [Annotated(m.name, m.ifcond) for m in members]},
+{'members': [self._gen_enum_member(m) for m in members],
+ 'values': [Annotated(m.name, m.ifcond) for m in members]},
 ifcond, features
 )
 
@@ -322,7 +332,7 @@ def visit_object_type_flat(self, name: str, info: 
Optional[QAPISourceInfo],
members: List[QAPISchemaObjectTypeMember],
  

[PATCH v2 0/5] qapi: Add feature flags to enum members

2021-10-09 Thread Markus Armbruster
PATCH 1+2 add feature flags to enum members.  Awkward due to an
introspection design mistake; see PATCH 1 for details.

PATCH 3+4 implement policy deprecated-input={reject,crash} for enum
values.

Policy deprecated-output=hide is not implemented, because we can't
hide a value without hiding the entire member, which is almost
certainly more than the requester of this policy bargained for.
Perhaps we want a new policy deprecated-output=hide-or-else-crash to
help us catch unwanted use of deprecated enum values.  Perhaps we want
deprecated-output=hide to behave that way together with
deprecated-input=crash.  Or even always.  Thoughts?

PATCH 5 puts the new feature flags to use.  It's RFC because it makes
sense only on top of Vladimir's deprecation of drive-backup.  See its
commit message for a reference.

I prefer to commit new features together with a use outside tests/.
PATCH 5 adds such a use, but it's RFC, because it depends on
Vladimir's work.  Perhaps another use pops up.  I can delay this work
in the hope of a use becoming ready, but the feature flags work I have
in the pipeline will eventually force my hand.

v2:
* Rebased with straightforward conflicts.
* PATCH 1-4: No longer RFC.
* PATCH 1: "Since" information fixed [Eric].  Commit message updated
  to reflect feedback.
* PATCH 2: Commit message amended to point out special feature flag
 'deprecated' is ignored at this stage.
* PATCH 4: Documentation updated.  Commit message tweaked.

Markus Armbruster (5):
  qapi: Enable enum member introspection to show more than name
  qapi: Add feature flags to enum members
  qapi: Move compat policy from QObject to generic visitor
  qapi: Implement deprecated-input={reject,crash} for enum values
  block: Deprecate transaction type drive-backup

 docs/devel/qapi-code-gen.rst  | 10 ---
 qapi/compat.json  |  3 +++
 qapi/introspect.json  | 24 +++--
 qapi/transaction.json |  5 +++-
 include/qapi/qobject-input-visitor.h  |  4 ---
 include/qapi/qobject-output-visitor.h |  4 ---
 include/qapi/util.h   |  6 -
 include/qapi/visitor-impl.h   |  3 +++
 include/qapi/visitor.h|  9 +++
 qapi/qapi-visit-core.c| 27 ---
 qapi/qmp-dispatch.c   |  4 +--
 qapi/qobject-input-visitor.c  | 14 +-
 qapi/qobject-output-visitor.c | 14 +-
 scripts/qapi/expr.py  |  3 ++-
 scripts/qapi/introspect.py| 19 ++---
 scripts/qapi/schema.py| 22 +--
 scripts/qapi/types.py | 17 +++-
 tests/qapi-schema/doc-good.json   |  5 +++-
 tests/qapi-schema/doc-good.out|  3 +++
 tests/qapi-schema/doc-good.txt|  3 +++
 .../qapi-schema/enum-dict-member-unknown.err  |  2 +-
 tests/qapi-schema/qapi-schema-test.json   |  3 ++-
 tests/qapi-schema/qapi-schema-test.out|  1 +
 tests/qapi-schema/test-qapi.py|  1 +
 24 files changed, 149 insertions(+), 57 deletions(-)

-- 
2.31.1




Re: [PATCH] hw/misc: Add a virtual pci device to dynamically attach memory to QEMU

2021-10-09 Thread david.dai
On Thu, Sep 30, 2021 at 12:33:30PM +0200, David Hildenbrand (da...@redhat.com) 
wrote:
> 
> 
> On 30.09.21 11:40, david.dai wrote:
> > On Wed, Sep 29, 2021 at 11:30:53AM +0200, David Hildenbrand 
> > (da...@redhat.com) wrote:
> > > 
> > > On 27.09.21 14:28, david.dai wrote:
> > > > On Mon, Sep 27, 2021 at 11:07:43AM +0200, David Hildenbrand 
> > > > (da...@redhat.com) wrote:
> > > > > 
> > > > > CAUTION: This email originated from outside of the organization. Do 
> > > > > not
> > > > > click links or open attachments unless you recognize the sender and 
> > > > > know the
> > > > > content is safe.
> > > > > 
> > > > > 
> > > > > On 27.09.21 10:27, Stefan Hajnoczi wrote:
> > > > > > On Sun, Sep 26, 2021 at 10:16:14AM +0800, David Dai wrote:
> > > > > > > Add a virtual pci to QEMU, the pci device is used to dynamically 
> > > > > > > attach memory
> > > > > > > to VM, so driver in guest can apply host memory in fly without 
> > > > > > > virtualization
> > > > > > > management software's help, such as libvirt/manager. The attached 
> > > > > > > memory is
> > > > > 
> > > > > We do have virtio-mem to dynamically attach memory to a VM. It could 
> > > > > be
> > > > > extended by a mechanism for the VM to request more/less memory, that's
> > > > > already a planned feature. But yeah, virito-mem memory is exposed as
> > > > > ordinary system RAM, not only via a BAR to mostly be managed by user 
> > > > > space
> > > > > completely.
> > > 
> > > There is a virtio-pmem spec proposal to expose the memory region via a PCI
> > > BAR. We could do something similar for virtio-mem, however, we would have 
> > > to
> > > wire that new model up differently in QEMU (it's no longer a "memory 
> > > device"
> > > like a DIMM then).
> > > 
> > > > > 
> > > > 
> > > > I wish virtio-mem can solve our problem, but it is a dynamic allocation 
> > > > mechanism
> > > > for system RAM in virtualization. In heterogeneous computing 
> > > > environments, the
> > > > attached memory usually comes from computing device, it should be 
> > > > managed separately.
> > > > we doesn't hope Linux MM controls it.
> > > 
> > > If that heterogeneous memory would have a dedicated node (which usually is
> > > the case IIRC) , and you let it manage by the Linux kernel (dax/kmem), you
> > > can bind the memory backend of virtio-mem to that special NUMA node. So 
> > > all
> > > memory managed by that virtio-mem device would come from that 
> > > heterogeneous
> > > memory.
> > > 
> > 
> > Yes, CXL type 2, 3 devices expose memory to host as a dedicated node, the 
> > node
> > is marked as soft_reserved_memory, dax/kmem can take over the node to 
> > create a
> > dax devcie. This dax device can be regarded as the memory backend of 
> > virtio-mem
> > 
> > I don't sure whether a dax device can be open by multiple VMs or host 
> > applications.
> 
> virito-mem currently relies on having a single sparse memory region (anon
> mmap, mmaped file, mmaped huge pages, mmap shmem) per VM. Although we can
> share memory with other processes, sharing with other VMs is not intended.
> Instead of actually mmaping parts dynamically (which can be quite
> expensive), virtio-mem relies on punching holes into the backend and
> dynamically allocating memory/file blocks/... on access.
> 
> So the easy way to make it work is:
> 
> a) Exposing the CXL memory to the buddy via dax/kmem, esulting in device
> memory getting managed by the buddy on a separate NUMA node.
>

Linux kernel buddy system? how to guarantee other applications don't apply 
memory
from it

>
> b) (optional) allocate huge pages on that separate NUMA node.
> c) Use ordinary memory-device-ram or memory-device-memfd (for huge pages),
> *bidning* the memory backend to that special NUMA node.
>
 
"-object memory-backend/device-ram or memory-device-memfd, id=mem0, size=768G"
How to bind backend memory to NUMA node

>
> This will dynamically allocate memory from that special NUMA node, resulting
> in the virtio-mem device completely being backed by that device memory,
> being able to dynamically resize the memory allocation.
> 
> 
> Exposing an actual devdax to the virtio-mem device, shared by multiple VMs
> isn't really what we want and won't work without major design changes. Also,
> I'm not so sure it's a very clean design: exposing memory belonging to other
> VMs to unrelated QEMU processes. This sounds like a serious security hole:
> if you managed to escalate to the QEMU process from inside the VM, you can
> access unrelated VM memory quite happily. You want an abstraction
> in-between, that makes sure each VM/QEMU process only sees private memory:
> for example, the buddy via dax/kmem.
> 
Hi David
Thanks for your suggestion, also sorry for my delayed reply due to my long 
vacation.
How does current virtio-mem dynamically attach memory to guest, via page fault?

Thanks,
David 


> -- 
> Thanks,
> 
> David / dhildenb
> 
> 





Re: [PATCH 4/6] meson: remove explicit extensions dependency file list

2021-10-09 Thread Marc-André Lureau
Hi

On Sat, Oct 9, 2021 at 2:09 AM  wrote:

> From: Marc-André Lureau 
>
> This is now generated automatically by depfile.py.
>
> Signed-off-by: Marc-André Lureau 
> ---
>  docs/meson.build  | 10 --
>  tests/qapi-schema/meson.build |  5 -
>  2 files changed, 4 insertions(+), 11 deletions(-)
>
> diff --git a/docs/meson.build b/docs/meson.build
> index be4dc30f39..6177c967ff 100644
> --- a/docs/meson.build
> +++ b/docs/meson.build
> @@ -37,15 +37,6 @@ endif
>  if build_docs
>SPHINX_ARGS += ['-Dversion=' + meson.project_version(), '-Drelease=' +
> config_host['PKGVERSION']]
>
> -  sphinx_extn_depends = [ meson.current_source_dir() /
> 'sphinx/depfile.py',
> -  meson.current_source_dir() / 'sphinx/hxtool.py',
> -  meson.current_source_dir() /
> 'sphinx/kerneldoc.py',
> -  meson.current_source_dir() /
> 'sphinx/kernellog.py',
> -  meson.current_source_dir() /
> 'sphinx/qapidoc.py',
> -  meson.current_source_dir() /
> 'sphinx/qmp_lexer.py',
> -  qapi_gen_depends ]
> -  sphinx_template_files = [ meson.project_source_root() /
> 'docs/_templates/footer.html' ]
> -
>have_ga = have_tools and config_host.has_key('CONFIG_GUEST_AGENT')
>
>man_pages = {
> @@ -77,7 +68,6 @@ if build_docs
>  output: 'docs.stamp',
>  input: files('conf.py'),
>  depfile: 'docs.d',
> -depend_files: [ sphinx_extn_depends,
> sphinx_template_files ],
>  command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
>'-Ddepfile_stamp=@OUTPUT0@',
>'-b', 'html', '-d', private_dir,
> diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build
> index df5acfd08b..a5eae6253f 100644
> --- a/tests/qapi-schema/meson.build
> +++ b/tests/qapi-schema/meson.build
> @@ -241,7 +241,8 @@ if build_docs
> output: ['doc-good.txt'],
> input: files('doc-good.json',
> 'doc-good.rst'),
> build_by_default: true,
> -   depend_files: sphinx_extn_depends,
> +   output: 'docs.stamp',
>

This line should be removed (it breaks the test)

+   depfile: 'docs.d',
> # We use -E to suppress Sphinx's caching,
> because
> # we want it to always really run the QAPI
> doc
> # generation code. It also means we don't
> @@ -250,6 +251,8 @@ if build_docs
>   '-b', 'text', '-E',
>   '-c',
> meson.project_source_root() / 'docs',
>   '-D', 'master_doc=doc-good',
> + '-Ddepfile=@DEPFILE@',
> + '-Ddepfile_stamp=@OUTPUT0@',
>   meson.current_source_dir(),
>   meson.current_build_dir()])
>
> --
> 2.33.0.721.g106298f7f9
>
>
>

-- 
Marc-André Lureau


Re: [PATCH RFC 1/5] qapi: Enable enum member introspection to show more than name

2021-10-09 Thread Markus Armbruster
Peter Krempa  writes:

> On Mon, Sep 20, 2021 at 11:08:59 +0200, Markus Armbruster wrote:
>> Peter Krempa  writes:
>> 
>> > On Wed, Sep 15, 2021 at 21:24:21 +0200, Markus Armbruster wrote:
>> >> The next commit will add feature flags to enum members.  There's a
>> >> problem, though: query-qmp-schema shows an enum type's members as an
>> >> array of member names (SchemaInfoEnum member @values).  If it showed
>> >> an array of objects with a name member, we could simply add more
>> >> members to these objects.  Since it's just strings, we can't.
>> >> 
>> >> I can see three ways to correct this design mistake:
>> >> 
>> >> 1. Do it the way we should have done it, plus compatibility goo.
>> >> 
>> >>We want a ['SchemaInfoEnumMember'] member in SchemaInfoEnum.  Since
>> >>changing @values would be a compatibility break, add a new member
>> >>@members instead.
>> >> 
>> >>@values is now redundant.  We should be able to get rid of it
>> >>eventually.
>> >> 
>> >>In my testing, output of qemu-system-x86_64's query-qmp-schema
>> >>grows by 11% (18.5KiB).
>> >
>> > I prefer this one. While the schema output grows, nobody is really
>> > reading it manually.
>> 
>> True, but growing schema output can only slow down client startup.
>> Negligible for libvirt, I presume?
>
> Libvirt employs caching, so unless it's the first VM started after a
> qemu/libvirt upgrade, the results are already processed and cached.

Good!

> In fact we don't even keep the full schema around, we just extract
> information and store them as capability bits. For now we didn't run
> into the need to have the full schema around when starting a VM.
>
> [...]
>
>> >> 3. Versioned query-qmp-schema.
>> >> 
>> >>query-qmp-schema provides either @values or @members.  The QMP
>> >>client can select which version it wants.
>> >
>> > At least for libvirt this poses a chicken & egg problem. We'd have to
>> > query the schema to see that it has the switch to do the selection and
>> > then probe with the modern one.
>> 
>> The simplest solution is to try the versions the management application
>> can understand in order of preference (newest to oldest) until one
>> succeeds.  I'd expect the first try to work most of the time.  Only when
>> you combine new libvirt with old QEMU, the fallback has to kick in.
>> 
>> Other parts of the management application should remain oblivous of the
>> differences.
>
> That would certainly work and be reasonably straightforward for libvirt
> to implement, but:
>  1) libvirt's code for using the QMP schema would be exactly the same as
> with approach 1), as we need to handle old clients too and the new
> way is simply a superset of what we have

Yes, libvirt would need the same code for processing old and new.  The
only difference would be how it decides which method to use.  With 1,
it's "if @members is present, use it, else @values".  With 2, it's "if
the version we use is new enough, use @members, else @values".

>  2) qemu's deprecation approach itself wouldn't be any easier in either
> of those scenarios
>
> Basically the only thing this would gain us is that if the deprecation
> period is over old clients which were not fixed could fail silently:
>
> Assuming that 'query-qmp-schema' gains a boolean option such as
> 'fancier-enums' and setting that to true returns the new format of
> schema, after the deprecation is over you could simply return an error
> if a caller omits 'fancier-enums' or sets it to false, which creates a
> clean cut for the removal.

Yes.

> With approach 1) itself, clients which were not adapted would start
> lacking information based on enum values.
>
> Now for those it depends on how they actually handled it until now. E.g.
> old libvirt would report that the QMP schema is broken if 'values' would
> be missing.

Which I consider the sensible thing to do.

> Whether that's a worthwhile thing to do? I'm not really persuaded. (And
> I'm biased since libvirt handles it correctly).

I think 3 has the following advantages over 1:

* As you noted, it ensures outmoded clients fail cleanly.  Not much of
  an advantage for clients that handle missing @values sensibly.
  Perhaps it could enable better error messages.

* It avoids duplicated contents in old an new format.  Not much of an
  advantage for clients that cache their schema interrogation.

* It can enable more radical introspection changes.  Without versioning,
  the common rules for compatible evolution apply (section
  "Compatibility considerations" in qapi-code-gen.rst).  With
  versioning, they don't.

I agree this is not really compelling just for the problem at hand.  We
can reconsider when we run into more problems.

>> We could of course try to reduce the number of roundtrips, say by
>> putting sufficient information into the QMP greeting (one roundtrip), or
>> the output of query-qmp-schema (try oldest to find the best one, then
>> try the best one unless it's the oldest).  I doubt that's 

[PATCH v4 3/3] multifd: Implement zerocopy write in multifd migration (multifd-zerocopy)

2021-10-09 Thread Leonardo Bras
Implement zerocopy on nocomp_send_write(), by making use of QIOChannel
zerocopy interface.

Change multifd_send_sync_main() so it can distinguish the last sync from
the setup and per-iteration ones, so a flush_zerocopy() can be called
at the last sync in order to make sure all RAM is sent before finishing
the migration.

Also make it return -1 if flush_zerocopy() fails, in order to cancel
the migration process, and avoid resuming the guest in the target host
without receiving all current RAM.

This will work fine on RAM migration because the RAM pages are not usually 
freed,
and there is no problem on changing the pages content between async_send() and
the actual sending of the buffer, because this change will dirty the page and
cause it to be re-sent on a next iteration anyway.

Given a lot of locked memory may be needed in order to use multid migration
with zerocopy enabled, make it optional by creating a new parameter
multifd-zerocopy on qapi, so low-privileged users can still perform multifd
migrations.

Signed-off-by: Leonardo Bras 
---
 qapi/migration.json   | 18 ++
 migration/migration.h |  1 +
 migration/multifd.h   |  2 +-
 migration/migration.c | 20 
 migration/multifd.c   | 33 -
 migration/ram.c   | 20 +---
 monitor/hmp-cmds.c|  4 
 7 files changed, 85 insertions(+), 13 deletions(-)

diff --git a/qapi/migration.json b/qapi/migration.json
index 88f07baedd..c4890cbb54 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -724,6 +724,11 @@
 #  will consume more CPU.
 #  Defaults to 1. (Since 5.0)
 #
+# @multifd-zerocopy: Controls behavior on sending memory pages on multifd 
migration.
+#When true, enables a zerocopy mechanism for sending memory
+#pages, if host does support it.
+#Defaults to false. (Since 6.2)
+#
 # @block-bitmap-mapping: Maps block nodes and bitmaps on them to
 #aliases for the purpose of dirty bitmap migration.  
Such
 #aliases may for example be the corresponding names on 
the
@@ -758,6 +763,7 @@
'xbzrle-cache-size', 'max-postcopy-bandwidth',
'max-cpu-throttle', 'multifd-compression',
'multifd-zlib-level' ,'multifd-zstd-level',
+  'multifd-zerocopy',
'block-bitmap-mapping' ] }
 
 ##
@@ -884,6 +890,11 @@
 #  will consume more CPU.
 #  Defaults to 1. (Since 5.0)
 #
+# @multifd-zerocopy: Controls behavior on sending memory pages on multifd 
migration.
+#When true, enables a zerocopy mechanism for sending memory
+#pages, if host does support it.
+#Defaults to false. (Since 6.2)
+#
 # @block-bitmap-mapping: Maps block nodes and bitmaps on them to
 #aliases for the purpose of dirty bitmap migration.  
Such
 #aliases may for example be the corresponding names on 
the
@@ -934,6 +945,7 @@
 '*multifd-compression': 'MultiFDCompression',
 '*multifd-zlib-level': 'uint8',
 '*multifd-zstd-level': 'uint8',
+   '*multifd-zerocopy': 'bool',
 '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } }
 
 ##
@@ -1080,6 +1092,11 @@
 #  will consume more CPU.
 #  Defaults to 1. (Since 5.0)
 #
+# @multifd-zerocopy: Controls behavior on sending memory pages on multifd 
migration.
+#When true, enables a zerocopy mechanism for sending memory
+#pages, if host does support it.
+#Defaults to false. (Since 6.2)
+#
 # @block-bitmap-mapping: Maps block nodes and bitmaps on them to
 #aliases for the purpose of dirty bitmap migration.  
Such
 #aliases may for example be the corresponding names on 
the
@@ -1128,6 +1145,7 @@
 '*multifd-compression': 'MultiFDCompression',
 '*multifd-zlib-level': 'uint8',
 '*multifd-zstd-level': 'uint8',
+   '*multifd-zerocopy': 'bool',
 '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } }
 
 ##
diff --git a/migration/migration.h b/migration/migration.h
index 7a5aa8c2fd..860d83cc41 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -338,6 +338,7 @@ int migrate_multifd_channels(void);
 MultiFDCompression migrate_multifd_compression(void);
 int migrate_multifd_zlib_level(void);
 int migrate_multifd_zstd_level(void);
+int migrate_multifd_zerocopy(void);
 
 int migrate_use_xbzrle(void);
 uint64_t migrate_xbzrle_cache_size(void);
diff --git a/migration/multifd.h b/migration/multifd.h
index 8d6751f5ed..8f5c5a6953 100644
--- a/migration/multifd.h
+++ b/migration/multifd.h
@@ -20,7 +20,7 @@ int multifd_load_cleanup(Error **errp);
 bool 

[PATCH v4 1/3] QIOChannel: Add io_writev_zerocopy & io_flush_zerocopy callbacks

2021-10-09 Thread Leonardo Bras
Adds io_async_writev and io_async_flush as optional callback to QIOChannelClass,
allowing the implementation of asynchronous writes by subclasses.

How to use them:
- Write data using qio_channel_writev_zerocopu(),
- Wait write completion with qio_channel_flush_zerocopy().

Notes:
As some zerocopy implementations work asynchronously, it's
recommended to keep the write buffer untouched until the return of
qio_channel_flush_zerocopy(), by the risk of sending an updated buffer
instead of the one at the write.

As the new callbacks are optional, if a subclass does not implement them, then:
- io_async_writev will return -1,
- io_async_flush will return 0 without changing anything.

Also, some functions like qio_channel_writev_full_all() were adapted to
receive a flag parameter. That allows shared code between zerocopy and
non-zerocopy writev.

Signed-off-by: Leonardo Bras 
---
 include/io/channel.h | 103 +++
 io/channel.c |  74 +++
 2 files changed, 141 insertions(+), 36 deletions(-)

diff --git a/include/io/channel.h b/include/io/channel.h
index 88988979f8..e7d4e1521f 100644
--- a/include/io/channel.h
+++ b/include/io/channel.h
@@ -32,12 +32,15 @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass,
 
 #define QIO_CHANNEL_ERR_BLOCK -2
 
+#define QIO_CHANNEL_WRITE_FLAG_ZEROCOPY 0x1
+
 typedef enum QIOChannelFeature QIOChannelFeature;
 
 enum QIOChannelFeature {
 QIO_CHANNEL_FEATURE_FD_PASS,
 QIO_CHANNEL_FEATURE_SHUTDOWN,
 QIO_CHANNEL_FEATURE_LISTEN,
+QIO_CHANNEL_FEATURE_WRITE_ZEROCOPY,
 };
 
 
@@ -136,6 +139,12 @@ struct QIOChannelClass {
   IOHandler *io_read,
   IOHandler *io_write,
   void *opaque);
+ssize_t (*io_writev_zerocopy)(QIOChannel *ioc,
+  const struct iovec *iov,
+  size_t niov,
+  Error **errp);
+int (*io_flush_zerocopy)(QIOChannel *ioc,
+  Error **errp);
 };
 
 /* General I/O handling functions */
@@ -222,12 +231,13 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc,
 
 
 /**
- * qio_channel_writev_full:
+ * qio_channel_writev_full_flags:
  * @ioc: the channel object
  * @iov: the array of memory regions to write data from
  * @niov: the length of the @iov array
  * @fds: an array of file handles to send
  * @nfds: number of file handles in @fds
+ * @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*)
  * @errp: pointer to a NULL-initialized error object
  *
  * Write data to the IO channel, reading it from the
@@ -242,6 +252,10 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc,
  * guaranteed. If the channel is non-blocking and no
  * data can be sent, it will return QIO_CHANNEL_ERR_BLOCK
  *
+ * If flag QIO_CHANNEL_WRITE_FLAG_ZEROCOPY is passed,
+ * function will return once each buffer was queued for
+ * sending.
+ *
  * If there are file descriptors to send, the @fds
  * array should be non-NULL and provide the handles.
  * All file descriptors will be sent if at least one
@@ -255,12 +269,15 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc,
  * or QIO_CHANNEL_ERR_BLOCK if no data is can be sent
  * and the channel is non-blocking
  */
-ssize_t qio_channel_writev_full(QIOChannel *ioc,
-const struct iovec *iov,
-size_t niov,
-int *fds,
-size_t nfds,
-Error **errp);
+ssize_t qio_channel_writev_full_flags(QIOChannel *ioc,
+  const struct iovec *iov,
+  size_t niov,
+  int *fds,
+  size_t nfds,
+  int flags,
+  Error **errp);
+#define qio_channel_writev_full(ioc, iov, niov, fds, nfds, errp) \
+qio_channel_writev_full_flags(ioc, iov, niov, fds, nfds, 0, errp)
 
 /**
  * qio_channel_readv_all_eof:
@@ -321,10 +338,11 @@ int qio_channel_readv_all(QIOChannel *ioc,
 
 
 /**
- * qio_channel_writev_all:
+ * qio_channel_writev_all_flags:
  * @ioc: the channel object
  * @iov: the array of memory regions to write data from
  * @niov: the length of the @iov array
+ * @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*)
  * @errp: pointer to a NULL-initialized error object
  *
  * Write data to the IO channel, reading it from the
@@ -339,10 +357,13 @@ int qio_channel_readv_all(QIOChannel *ioc,
  *
  * Returns: 0 if all bytes were written, or -1 on error
  */
-int qio_channel_writev_all(QIOChannel *ioc,
-   const struct iovec *iov,
-   size_t niov,
-   Error **erp);
+int qio_channel_writev_all_flags(QIOChannel *ioc,
+ const struct 

[PATCH v4 2/3] QIOChannelSocket: Implement io_writev_zerocopy & io_flush_zerocopy for CONFIG_LINUX

2021-10-09 Thread Leonardo Bras
For CONFIG_LINUX, implement the new optional callbacks io_write_zerocopy and
io_flush_zerocopy on QIOChannelSocket, but enables it only when MSG_ZEROCOPY
feature is available in the host kernel, which is checked on
qio_channel_socket_connect_sync()

qio_channel_socket_writev() contents were moved to a helper function
qio_channel_socket_writev_flags() which accepts an extra argument for flags.
(This argument is passed directly to sendmsg().

The above helper function is used to implement qio_channel_socket_writev(),
with flags = 0, keeping it's behavior unchanged, and
qio_channel_socket_writev_zerocopy() with flags = MSG_ZEROCOPY.

qio_channel_socket_flush_zerocopy() was implemented by counting how many times
sendmsg(...,MSG_ZEROCOPY) was sucessfully called, and then reading the
socket's error queue, in order to find how many of them finished sending.
Flush will loop until those counters are the same, or until some error ocurs.

A new function qio_channel_socket_poll() was also created in order to avoid
busy-looping recvmsg() in qio_channel_socket_flush_zerocopy() while waiting for
updates in socket's error queue.

Notes on using writev_zerocopy():
1: Buffer
- As MSG_ZEROCOPY tells the kernel to use the same user buffer to avoid copying,
some caution is necessary to avoid overwriting any buffer before it's sent.
If something like this happen, a newer version of the buffer may be sent 
instead.
- If this is a problem, it's recommended to call flush_zerocopy() before freeing
or re-using the buffer.

2: Locked memory
- When using MSG_ZERCOCOPY, the buffer memory will be locked after queued, and
unlocked after it's sent.
- Depending on the size of each buffer, and how often it's sent, it may require
a larger amount of locked memory than usually available to non-root user.
- If the required amount of locked memory is not available, writev_zerocopy
will return an error, which can abort an operation like migration,
- Because of this, when an user code wants to add zerocopy as a feature, it
requires a mechanism to disable it, so it can still be acessible to less
privileged users.

Signed-off-by: Leonardo Bras 
---
 include/io/channel-socket.h |   2 +
 include/io/channel.h|   1 +
 io/channel-socket.c | 180 ++--
 3 files changed, 173 insertions(+), 10 deletions(-)

diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h
index e747e63514..81d04baa4c 100644
--- a/include/io/channel-socket.h
+++ b/include/io/channel-socket.h
@@ -47,6 +47,8 @@ struct QIOChannelSocket {
 socklen_t localAddrLen;
 struct sockaddr_storage remoteAddr;
 socklen_t remoteAddrLen;
+ssize_t zerocopy_queued;
+ssize_t zerocopy_sent;
 };
 
 
diff --git a/include/io/channel.h b/include/io/channel.h
index e7d4e1521f..9d74629226 100644
--- a/include/io/channel.h
+++ b/include/io/channel.h
@@ -31,6 +31,7 @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass,
 
 
 #define QIO_CHANNEL_ERR_BLOCK -2
+#define QIO_CHANNEL_ERR_NOBUFS -3
 
 #define QIO_CHANNEL_WRITE_FLAG_ZEROCOPY 0x1
 
diff --git a/io/channel-socket.c b/io/channel-socket.c
index 606ec97cf7..6cc42057b2 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -26,6 +26,10 @@
 #include "io/channel-watch.h"
 #include "trace.h"
 #include "qapi/clone-visitor.h"
+#ifdef CONFIG_LINUX
+#include 
+#include 
+#endif
 
 #define SOCKET_MAX_FDS 16
 
@@ -55,6 +59,8 @@ qio_channel_socket_new(void)
 
 sioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET));
 sioc->fd = -1;
+sioc->zerocopy_queued = 0;
+sioc->zerocopy_sent = 0;
 
 ioc = QIO_CHANNEL(sioc);
 qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
@@ -140,6 +146,7 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,
 Error **errp)
 {
 int fd;
+int ret, v = 1;
 
 trace_qio_channel_socket_connect_sync(ioc, addr);
 fd = socket_connect(addr, errp);
@@ -154,6 +161,17 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,
 return -1;
 }
 
+#ifdef CONFIG_LINUX
+ret = qemu_setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, , sizeof(v));
+if (ret < 0) {
+/* Zerocopy not available on host */
+return 0;
+}
+
+qio_channel_set_feature(QIO_CHANNEL(ioc),
+QIO_CHANNEL_FEATURE_WRITE_ZEROCOPY);
+#endif
+
 return 0;
 }
 
@@ -520,12 +538,13 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
 return ret;
 }
 
-static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
- const struct iovec *iov,
- size_t niov,
- int *fds,
- size_t nfds,
- Error **errp)
+static ssize_t qio_channel_socket_writev_flags(QIOChannel *ioc,
+   const struct iovec *iov,
+   

[PATCH v4 0/3] MSG_ZEROCOPY for multifd

2021-10-09 Thread Leonardo Bras
This patch series intends to enable MSG_ZEROCOPY in QIOChannel, and make
use of it for multifd migration performance improvement.

Patch #1 creates new callbacks for QIOChannel, allowing the implementation
of zerocopy writing.

Patch #2 implements writev_zerocopy and flush_zerocopy on QIOChannelSocket,
making use of MSG_ZEROCOPY on Linux.

Patch #3 Makes use of QIOChannelSocket zerocopy implementation on
nocomp multifd migration.

Results:
So far, the resource usage of __sys_sendmsg() reduced 15 times, and the
overall migration took 13-22% less time, based in synthetic workload.

The objective is to reduce migration time in hosts with heavy cpu usage.

---
Changes since v3:
- QIOChannel interface names changed from io_async_{writev,flush} to
  io_{writev,flush}_zerocopy
- Instead of falling back in case zerocopy is not implemented, return
  error and abort operation.
- Flush now waits as long as needed, or return error in case anything 
  goes wrong, aborting the operation.
- Zerocopy is now conditional in multifd, being set by parameter 
  multifd-zerocopy
- Moves zerocopy_flush to multifd_send_sync_main() from multifd_save_cleanup
  so migration can abort if flush goes wrong.
- Several other small improvements

Changes since v2:
- Patch #1: One more fallback
- Patch #2: Fall back to sync if fails to lock buffer memory in MSG_ZEROCOPY 
send.

Changes since v1:
- Reimplemented the patchset using async_write + async_flush approach.
- Implemented a flush to be able to tell whenever all data was written.

Leonardo Bras (3):
  QIOChannel: Add io_writev_zerocopy & io_flush_zerocopy callbacks
  QIOChannelSocket: Implement io_writev_zerocopy & io_flush_zerocopy for
CONFIG_LINUX
  multifd: Implement zerocopy write in multifd migration
(multifd-zerocopy)

 qapi/migration.json |  18 
 include/io/channel-socket.h |   2 +
 include/io/channel.h| 104 +
 migration/migration.h   |   1 +
 migration/multifd.h |   2 +-
 io/channel-socket.c | 180 ++--
 io/channel.c|  74 +++
 migration/migration.c   |  20 
 migration/multifd.c |  33 ++-
 migration/ram.c |  20 ++--
 monitor/hmp-cmds.c  |   4 +
 11 files changed, 399 insertions(+), 59 deletions(-)

-- 
2.33.0




Re: [PATCH 2/4] hw/i386/sgx: Have sgx_epc_get_section() return a boolean

2021-10-09 Thread Yang Zhong
On Thu, Oct 07, 2021 at 07:56:10PM +0200, Philippe Mathieu-Daudé wrote:
> Signed-off-by: Philippe Mathieu-Daudé 
> ---
>  include/hw/i386/sgx-epc.h | 2 +-
>  hw/i386/sgx-stub.c| 2 +-
>  hw/i386/sgx.c | 6 +++---
>  3 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h
> index 65a68ca753a..a6a65be854f 100644
> --- a/include/hw/i386/sgx-epc.h
> +++ b/include/hw/i386/sgx-epc.h
> @@ -55,7 +55,7 @@ typedef struct SGXEPCState {
>  int nr_sections;
>  } SGXEPCState;
>  
> -int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size);
> +bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size);
>  
>  static inline uint64_t sgx_epc_above_4g_end(SGXEPCState *sgx_epc)
>  {
> diff --git a/hw/i386/sgx-stub.c b/hw/i386/sgx-stub.c
> index 3be9f5ca32c..45c473119ef 100644
> --- a/hw/i386/sgx-stub.c
> +++ b/hw/i386/sgx-stub.c
> @@ -20,7 +20,7 @@ void pc_machine_init_sgx_epc(PCMachineState *pcms)
>  memset(>sgx_epc, 0, sizeof(SGXEPCState));
>  }
>  
> -int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
> +bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
>  {
>  g_assert_not_reached();
>  }
> diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c
> index e481e9358f1..29724ff8f08 100644
> --- a/hw/i386/sgx.c
> +++ b/hw/i386/sgx.c
> @@ -115,13 +115,13 @@ SGXInfo *sgx_get_info(Error **errp)
>  return info;
>  }
>  
> -int sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
> +bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
>  {
>  PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
>  SGXEPCDevice *epc;
>  
>  if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) {
> -return 1;
> +return true;


If return boolean, here should be return false, Sean wrote this(return 0 or 1) 
like Linux kernel did.  


>  }
>  
>  epc = pcms->sgx_epc.sections[section_nr];
> @@ -129,7 +129,7 @@ int sgx_epc_get_section(int section_nr, uint64_t *addr, 
> uint64_t *size)
>  *addr = epc->addr;
>  *size = memory_device_get_region_size(MEMORY_DEVICE(epc), _fatal);
>  
> -return 0;
> +return false;

Here should be return true.

Then in the ./target/i386/cpu.c file,

 if (sgx_epc_get_section(count - 2, _addr, _size))

 should be

 if (!sgx_epc_get_section(count - 2, _addr, _size))


Yang


>  }
>  
>  void pc_machine_init_sgx_epc(PCMachineState *pcms)
> -- 
> 2.31.1