[Spice-commits] 24 commits - disas/sparc.c docs/multiseat.txt hw/input include/ui qapi-schema.json qemu-options.hx qmp-commands.hx qmp.c target-sparc/ldst_helper.c target-sparc/translate.c ui/spice-core.c ui/spice-display.c ui/vnc.c ui/vnc.h vl.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Fri Jan 23 03:39:49 PST 2015


 disas/sparc.c              |   32 --
 docs/multiseat.txt         |   18 -
 hw/input/hid.c             |   23 +
 include/ui/console.h       |   18 -
 qapi-schema.json           |   85 +++++-
 qemu-options.hx            |    3 
 qmp-commands.hx            |    5 
 qmp.c                      |   15 -
 target-sparc/ldst_helper.c |   10 
 target-sparc/translate.c   |   26 -
 ui/spice-core.c            |    9 
 ui/spice-display.c         |    6 
 ui/vnc.c                   |  634 +++++++++++++++++++++++++++++++++------------
 ui/vnc.h                   |    5 
 vl.c                       |   41 --
 15 files changed, 666 insertions(+), 264 deletions(-)

New commits:
commit 8f970eff6e318524f189f105c236e47633759890
Merge: adeecf1 0ee4de5
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 22 17:41:59 2015 +0000

    Merge remote-tracking branch 'remotes/kraxel/tags/pull-input-20150122-1' into staging
    
    input: misc fixes.
    
    # gpg: Signature made Thu 22 Jan 2015 11:27:37 GMT using RSA key ID D3E87138
    # gpg: Good signature from "Gerd Hoffmann (work) <kraxel at redhat.com>"
    # gpg:                 aka "Gerd Hoffmann <gerd at kraxel.org>"
    # gpg:                 aka "Gerd Hoffmann (private) <kraxel at gmail.com>"
    
    * remotes/kraxel/tags/pull-input-20150122-1:
      hw/input/hid.c Fix capslock hid code
      hid: handle full ptr queues in post_load
      input: improve docs for input-send-event qmp command
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

commit adeecf14d668f5f0a73c9be91772e15b4f8727f3
Merge: b3a4755 51a0909
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 22 13:56:11 2015 +0000

    Merge remote-tracking branch 'remotes/spice/tags/pull-spice-20150122-1' into staging
    
    spice: fix coverity defect, add unix address support
    
    # gpg: Signature made Thu 22 Jan 2015 11:17:24 GMT using RSA key ID D3E87138
    # gpg: Good signature from "Gerd Hoffmann (work) <kraxel at redhat.com>"
    # gpg:                 aka "Gerd Hoffmann <gerd at kraxel.org>"
    # gpg:                 aka "Gerd Hoffmann (private) <kraxel at gmail.com>"
    
    * remotes/spice/tags/pull-spice-20150122-1:
      spice: fix coverity reported defect in display code
      spice: add unix address support
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

commit b3a4755a67a52aa7297eb8927b482d09dabdefec
Merge: a805ca5 4478aa7
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 22 12:14:19 2015 +0000

    Merge remote-tracking branch 'remotes/kraxel/tags/pull-vnc-20150122-1' into staging
    
    vnc: add support for multiple vnc displays
    
    # gpg: Signature made Thu 22 Jan 2015 11:00:54 GMT using RSA key ID D3E87138
    # gpg: Good signature from "Gerd Hoffmann (work) <kraxel at redhat.com>"
    # gpg:                 aka "Gerd Hoffmann <gerd at kraxel.org>"
    # gpg:                 aka "Gerd Hoffmann (private) <kraxel at gmail.com>"
    
    * remotes/kraxel/tags/pull-vnc-20150122-1:
      monitor: add vnc websockets
      monitor: add query-vnc-servers command
      vnc: factor out qmp_query_client_list
      vnc: track & limit connections
      vnc: update docs/multiseat.txt
      vnc: allow binding servers to qemu consoles
      vnc: switch to QemuOpts, allow multiple servers
      vnc: add display id to acl names
      vnc: remove unused DisplayState parameter, add id instead.
      vnc: remove vnc_display global
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

commit 0ee4de5840ccc1072459ec68062bfb63c888a94d
Author: Dinar Valeev <dvaleev at suse.com>
Date:   Wed Jan 21 23:48:41 2015 +0100

    hw/input/hid.c Fix capslock hid code
    
    When ever USB keyboard is used, e.g. '-usbdevice keyboard' pressing
    caps lock key send 0x32 hid code, which is treated as backslash.
    Instead it should be 0x39 code. This affects sending uppercase keys,
    as they typed whith caps lock active.
    
    While on x86 this can be workarounded by using ps/2 protocol. On
    Power it is crusial as we don't have anything else than USB.
    
    This is fixes guest automation tasts over vnc.
    
    Signed-off-by: Dinar Valeev <dvaleev at suse.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hw/input/hid.c b/hw/input/hid.c
index ad18555..6841cb8 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -41,7 +41,7 @@ static const uint8_t hid_usage_keys[0x100] = {
     0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
     0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
     0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
-    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+    0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
     0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
     0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
     0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
commit ba4d26064e8c42711a1a6eb287cedac75deb1478
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Nov 27 10:02:35 2014 +0100

    hid: handle full ptr queues in post_load
    
    Cc: Dr. David Alan Gilbert <dgilbert at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Tested-by: Gonglei <arei.gonglei at huawei.com>
    Reviewed-by: Gonglei <arei.gonglei at huawei.com>

diff --git a/hw/input/hid.c b/hw/input/hid.c
index 148c003..ad18555 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -514,6 +514,27 @@ static int hid_post_load(void *opaque, int version_id)
     HIDState *s = opaque;
 
     hid_set_next_idle(s);
+
+    if (s->n == QUEUE_LENGTH && (s->kind == HID_TABLET ||
+                                 s->kind == HID_MOUSE)) {
+        /*
+         * Handle ptr device migration from old qemu with full queue.
+         *
+         * Throw away everything but the last event, so we propagate
+         * at least the current button state to the guest.  Also keep
+         * current position for the tablet, signal "no motion" for the
+         * mouse.
+         */
+        HIDPointerEvent evt;
+        evt = s->ptr.queue[(s->head+s->n) & QUEUE_MASK];
+        if (s->kind == HID_MOUSE) {
+            evt.xdx = 0;
+            evt.ydy = 0;
+        }
+        s->ptr.queue[0] = evt;
+        s->head = 0;
+        s->n = 1;
+    }
     return 0;
 }
 
commit 4083ae311d51edf93e2e163f4af2b22a1d0952cc
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Fri Nov 21 10:25:57 2014 +0100

    input: improve docs for input-send-event qmp command
    
    Text partly suggested by Markus Armbruster <armbru at redhat.com>
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index fbfc52f..f5b1ed1 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3258,6 +3258,18 @@
 # Send input event(s) to guest.
 #
 # @console: #optional console to send event(s) to.
+#           This parameter can be used to send the input event to
+#           specific input devices in case (a) multiple input devices
+#           of the same kind are added to the virtual machine and (b)
+#           you have configured input routing (see docs/multiseat.txt)
+#           for those input devices.  If input routing is not
+#           configured this parameter has no effect.
+#           If @console is missing, only devices that aren't associated
+#           with a console are admissible.
+#           If @console is specified, it must exist, and both devices
+#           associated with that console and devices not associated with a
+#           console are admissible, but the former take precedence.
+
 #
 # @events: List of InputEvent union.
 #
commit a805ca54015bd123e2bc2454ec59619d0ed106c2
Merge: 699eae1 7230818
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Thu Jan 22 11:16:20 2015 +0000

    Merge remote-tracking branch 'remotes/mcayland/tags/qemu-sparc-signed' into staging
    
    qemu-sparc update
    
    # gpg: Signature made Wed 21 Jan 2015 16:56:31 GMT using RSA key ID AE0F321F
    # gpg: Good signature from "Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>"
    
    * remotes/mcayland/tags/qemu-sparc-signed:
      disas/sparc: Remove unused data sparc_opcode_archs[]
      target-sparc: Mark gen_load_trap_state_at_tl() as !CONFIG_USER_ONLY
      target-sparc: is_translating_asi() is TARGET_SPARC64 only
      target-sparc: address_mask(), asi_address_mask() are TARGET_SPARC64 only
      target-sparc: Remove unused gen_op_subi_cc and gen_op_addi_cc
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>

commit 4478aa768ccefcc5b234c23d035435fd71b932f6
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Dec 10 09:49:39 2014 +0100

    monitor: add vnc websockets
    
    Add websockets bool to VncBasicInfo, report websocket server sockets,
    flag websocket client connections.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index 24f62a4..eec1d22 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -672,12 +672,15 @@
 #
 # @family: address family
 #
+# @websocket: true in case the socket is a websocket (since 2.3).
+#
 # Since: 2.1
 ##
 { 'type': 'VncBasicInfo',
   'data': { 'host': 'str',
             'service': 'str',
-            'family': 'NetworkAddressFamily' } }
+            'family': 'NetworkAddressFamily',
+            'websocket': 'bool' } }
 
 ##
 # @VncServerInfo
diff --git a/ui/vnc.c b/ui/vnc.c
index c85d9c3..a742c90 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -353,6 +353,9 @@ static VncClientInfo *qmp_query_vnc_client(const VncState *client)
     info->base->host = g_strdup(host);
     info->base->service = g_strdup(serv);
     info->base->family = inet_netfamily(sa.ss_family);
+#ifdef CONFIG_VNC_WS
+    info->base->websocket = client->websocket;
+#endif
 
 #ifdef CONFIG_VNC_TLS
     if (client->tls.session && client->tls.dname) {
@@ -457,6 +460,7 @@ out_error:
 }
 
 static VncBasicInfoList *qmp_query_server_entry(int socket,
+                                                bool websocket,
                                                 VncBasicInfoList *prev)
 {
     VncBasicInfoList *list;
@@ -477,6 +481,7 @@ static VncBasicInfoList *qmp_query_server_entry(int socket,
     info->host = g_strdup(host);
     info->service = g_strdup(serv);
     info->family = inet_netfamily(sa.ss_family);
+    info->websocket = websocket;
 
     list = g_new0(VncBasicInfoList, 1);
     list->value = info;
@@ -572,12 +577,13 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
             info->display = g_strdup(dev->id);
         }
         if (vd->lsock != -1) {
-            info->server = qmp_query_server_entry(vd->lsock,
+            info->server = qmp_query_server_entry(vd->lsock, false,
                                                   info->server);
         }
 #ifdef CONFIG_VNC_WS
         if (vd->lwebsock != -1) {
-            /* TODO */
+            info->server = qmp_query_server_entry(vd->lwebsock, true,
+                                                  info->server);
         }
 #endif
 
@@ -3305,10 +3311,13 @@ void vnc_display_open(const char *id, Error **errp)
 {
     VncDisplay *vs = vnc_display_find(id);
     QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
-    const char *display, *websocket, *share, *device_id;
+    const char *display, *share, *device_id;
     QemuConsole *con;
     int password = 0;
     int reverse = 0;
+#ifdef CONFIG_VNC_WS
+    const char *websocket;
+#endif
 #ifdef CONFIG_VNC_TLS
     int tls = 0, x509 = 0;
     const char *path;
commit df887684603a4b3b0c623090a6b419dc70f22c32
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Dec 17 15:49:44 2014 +0100

    monitor: add query-vnc-servers command
    
    Add new query vnc qmp command, for the lack of better ideas just name it
    "query-vnc-servers".  Changes over query-vnc:
    
     * It returns a list of vnc servers, so multiple vnc server instances
       are covered.
     * Each vnc server returns a list of server sockets.  Followup patch
       will use that to also report websockets.  In case we add support for
       multiple server sockets server sockets (to better support ipv4+ipv6
       dualstack) we can add them to the list too.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index fbfc52f..24f62a4 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -751,6 +751,63 @@
            '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
 
 ##
+# @VncPriAuth:
+#
+# vnc primary authentication method.
+#
+# Since: 2.3
+##
+{ 'enum': 'VncPrimaryAuth',
+  'data': [ 'none', 'vnc', 'ra2', 'ra2ne', 'tight', 'ultra',
+            'tls', 'vencrypt', 'sasl' ] }
+
+##
+# @VncVencryptSubAuth:
+#
+# vnc sub authentication method with vencrypt.
+#
+# Since: 2.3
+##
+{ 'enum': 'VncVencryptSubAuth',
+  'data': [ 'plain',
+            'tls-none',  'x509-none',
+            'tls-vnc',   'x509-vnc',
+            'tls-plain', 'x509-plain',
+            'tls-sasl',  'x509-sasl' ] }
+
+##
+# @VncInfo2:
+#
+# Information about a vnc server
+#
+# @id: vnc server name.
+#
+# @server: A list of @VncBasincInfo describing all listening sockets.
+#          The list can be empty (in case the vnc server is disabled).
+#          It also may have multiple entries: normal + websocket,
+#          possibly also ipv4 + ipv6 in the future.
+#
+# @clients: A list of @VncClientInfo of all currently connected clients.
+#           The list can be empty, for obvious reasons.
+#
+# @auth: The current authentication type used by the server
+#
+# @vencrypt: #optional The vencrypt sub authentication type used by the server,
+#            only specified in case auth == vencrypt.
+#
+# @display: #optional The display device the vnc server is linked to.
+#
+# Since: 2.3
+##
+{ 'type': 'VncInfo2',
+  'data': { 'id'        : 'str',
+            'server'    : ['VncBasicInfo'],
+            'clients'   : ['VncClientInfo'],
+            'auth'      : 'VncPrimaryAuth',
+            '*vencrypt' : 'VncVencryptSubAuth',
+            '*display'  : 'str' } }
+
+##
 # @query-vnc:
 #
 # Returns information about the current VNC server
@@ -762,6 +819,17 @@
 { 'command': 'query-vnc', 'returns': 'VncInfo' }
 
 ##
+# @query-vnc-servers:
+#
+# Returns a list of vnc servers.  The list can be empty.
+#
+# Returns: a list of @VncInfo2
+#
+# Since: 2.3
+##
+{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'] }
+
+##
 # @SpiceBasicInfo
 #
 # The basic information for SPICE network connection
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 8957201..c5f16dd 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2867,6 +2867,11 @@ EQMP
         .args_type  = "",
         .mhandler.cmd_new = qmp_marshal_input_query_vnc,
     },
+    {
+        .name       = "query-vnc-servers",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_vnc_servers,
+    },
 
 SQMP
 query-spice
diff --git a/ui/vnc.c b/ui/vnc.c
index cd757a3..c85d9c3 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -456,6 +456,139 @@ out_error:
     return NULL;
 }
 
+static VncBasicInfoList *qmp_query_server_entry(int socket,
+                                                VncBasicInfoList *prev)
+{
+    VncBasicInfoList *list;
+    VncBasicInfo *info;
+    struct sockaddr_storage sa;
+    socklen_t salen = sizeof(sa);
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+
+    if (getsockname(socket, (struct sockaddr *)&sa, &salen) < 0 ||
+        getnameinfo((struct sockaddr *)&sa, salen,
+                    host, sizeof(host), serv, sizeof(serv),
+                    NI_NUMERICHOST | NI_NUMERICSERV) < 0) {
+        return prev;
+    }
+
+    info = g_new0(VncBasicInfo, 1);
+    info->host = g_strdup(host);
+    info->service = g_strdup(serv);
+    info->family = inet_netfamily(sa.ss_family);
+
+    list = g_new0(VncBasicInfoList, 1);
+    list->value = info;
+    list->next = prev;
+    return list;
+}
+
+static void qmp_query_auth(VncDisplay *vd, VncInfo2 *info)
+{
+    switch (vd->auth) {
+    case VNC_AUTH_VNC:
+        info->auth = VNC_PRIMARY_AUTH_VNC;
+        break;
+    case VNC_AUTH_RA2:
+        info->auth = VNC_PRIMARY_AUTH_RA2;
+        break;
+    case VNC_AUTH_RA2NE:
+        info->auth = VNC_PRIMARY_AUTH_RA2NE;
+        break;
+    case VNC_AUTH_TIGHT:
+        info->auth = VNC_PRIMARY_AUTH_TIGHT;
+        break;
+    case VNC_AUTH_ULTRA:
+        info->auth = VNC_PRIMARY_AUTH_ULTRA;
+        break;
+    case VNC_AUTH_TLS:
+        info->auth = VNC_PRIMARY_AUTH_TLS;
+        break;
+    case VNC_AUTH_VENCRYPT:
+        info->auth = VNC_PRIMARY_AUTH_VENCRYPT;
+#ifdef CONFIG_VNC_TLS
+        info->has_vencrypt = true;
+        switch (vd->subauth) {
+        case VNC_AUTH_VENCRYPT_PLAIN:
+            info->vencrypt = VNC_VENCRYPT_SUB_AUTH_PLAIN;
+            break;
+        case VNC_AUTH_VENCRYPT_TLSNONE:
+            info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_NONE;
+            break;
+        case VNC_AUTH_VENCRYPT_TLSVNC:
+            info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_VNC;
+            break;
+        case VNC_AUTH_VENCRYPT_TLSPLAIN:
+            info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_PLAIN;
+            break;
+        case VNC_AUTH_VENCRYPT_X509NONE:
+            info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_NONE;
+            break;
+        case VNC_AUTH_VENCRYPT_X509VNC:
+            info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_VNC;
+            break;
+        case VNC_AUTH_VENCRYPT_X509PLAIN:
+            info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_PLAIN;
+            break;
+        case VNC_AUTH_VENCRYPT_TLSSASL:
+            info->vencrypt = VNC_VENCRYPT_SUB_AUTH_TLS_SASL;
+            break;
+        case VNC_AUTH_VENCRYPT_X509SASL:
+            info->vencrypt = VNC_VENCRYPT_SUB_AUTH_X509_SASL;
+            break;
+        default:
+            info->has_vencrypt = false;
+            break;
+        }
+#endif
+        break;
+    case VNC_AUTH_SASL:
+        info->auth = VNC_PRIMARY_AUTH_SASL;
+        break;
+    case VNC_AUTH_NONE:
+    default:
+        info->auth = VNC_PRIMARY_AUTH_NONE;
+        break;
+    }
+}
+
+VncInfo2List *qmp_query_vnc_servers(Error **errp)
+{
+    VncInfo2List *item, *prev = NULL;
+    VncInfo2 *info;
+    VncDisplay *vd;
+    DeviceState *dev;
+
+    QTAILQ_FOREACH(vd, &vnc_displays, next) {
+        info = g_new0(VncInfo2, 1);
+        info->id = g_strdup(vd->id);
+        info->clients = qmp_query_client_list(vd);
+        qmp_query_auth(vd, info);
+        if (vd->dcl.con) {
+            dev = DEVICE(object_property_get_link(OBJECT(vd->dcl.con),
+                                                  "device", NULL));
+            info->has_display = true;
+            info->display = g_strdup(dev->id);
+        }
+        if (vd->lsock != -1) {
+            info->server = qmp_query_server_entry(vd->lsock,
+                                                  info->server);
+        }
+#ifdef CONFIG_VNC_WS
+        if (vd->lwebsock != -1) {
+            /* TODO */
+        }
+#endif
+
+        item = g_new0(VncInfo2List, 1);
+        item->value = info;
+        item->next = prev;
+        prev = item;
+    }
+    return prev;
+}
+
 /* TODO
    1) Get the queue working for IO.
    2) there is some weirdness when using the -S option (the screen is grey
commit 2d29a4368c3c00a5cf200f29b3dfd32bc4fb2c31
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Dec 9 15:27:39 2014 +0100

    vnc: factor out qmp_query_client_list
    
    so we can reuse it for the new vnc query command.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index 8c40c8f..cd757a3 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -385,6 +385,20 @@ static VncDisplay *vnc_display_find(const char *id)
     return NULL;
 }
 
+static VncClientInfoList *qmp_query_client_list(VncDisplay *vd)
+{
+    VncClientInfoList *cinfo, *prev = NULL;
+    VncState *client;
+
+    QTAILQ_FOREACH(client, &vd->clients, next) {
+        cinfo = g_new0(VncClientInfoList, 1);
+        cinfo->value = qmp_query_vnc_client(client);
+        cinfo->next = prev;
+        prev = cinfo;
+    }
+    return prev;
+}
+
 VncInfo *qmp_query_vnc(Error **errp)
 {
     VncInfo *info = g_malloc0(sizeof(*info));
@@ -393,30 +407,16 @@ VncInfo *qmp_query_vnc(Error **errp)
     if (vd == NULL || vd->display == NULL) {
         info->enabled = false;
     } else {
-        VncClientInfoList *cur_item = NULL;
         struct sockaddr_storage sa;
         socklen_t salen = sizeof(sa);
         char host[NI_MAXHOST];
         char serv[NI_MAXSERV];
-        VncState *client;
 
         info->enabled = true;
 
         /* for compatibility with the original command */
         info->has_clients = true;
-
-        QTAILQ_FOREACH(client, &vd->clients, next) {
-            VncClientInfoList *cinfo = g_malloc0(sizeof(*info));
-            cinfo->value = qmp_query_vnc_client(client);
-
-            /* XXX: waiting for the qapi to support GSList */
-            if (!cur_item) {
-                info->clients = cur_item = cinfo;
-            } else {
-                cur_item->next = cinfo;
-                cur_item = cinfo;
-            }
-        }
+        info->clients = qmp_query_client_list(vd);
 
         if (vd->lsock == -1) {
             return info;
commit e5f34cdd2da54f28d90889a3afd15fad2d6105ff
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Oct 2 12:09:34 2014 +0200

    vnc: track & limit connections
    
    Also track the number of connections in "connecting" and "shared" state
    (in addition to the "exclusive" state).  Apply a configurable limit to
    these connections.
    
    The logic to apply the limit to connections in "shared" state is pretty
    simple:  When the limit is reached no new connections are allowed.
    
    The logic to apply the limit to connections in "connecting" state (this
    is the state you are in *before* successful authentication) is
    slightly different:  A new connect kicks out the oldest client which is
    still in "connecting" state.  This avoids a easy DoS by unauthenticated
    users by simply opening connections until the limit is reached.
    
    Cc: Dr. David Alan Gilbert <dgilbert at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index 091e809..8c40c8f 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -68,12 +68,34 @@ static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
             vs->csock, mn[vs->share_mode], mn[mode]);
 #endif
 
-    if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
+    switch (vs->share_mode) {
+    case VNC_SHARE_MODE_CONNECTING:
+        vs->vd->num_connecting--;
+        break;
+    case VNC_SHARE_MODE_SHARED:
+        vs->vd->num_shared--;
+        break;
+    case VNC_SHARE_MODE_EXCLUSIVE:
         vs->vd->num_exclusive--;
+        break;
+    default:
+        break;
     }
+
     vs->share_mode = mode;
-    if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
+
+    switch (vs->share_mode) {
+    case VNC_SHARE_MODE_CONNECTING:
+        vs->vd->num_connecting++;
+        break;
+    case VNC_SHARE_MODE_SHARED:
+        vs->vd->num_shared++;
+        break;
+    case VNC_SHARE_MODE_EXCLUSIVE:
         vs->vd->num_exclusive++;
+        break;
+    default:
+        break;
     }
 }
 
@@ -2337,6 +2359,11 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
     }
     vnc_set_share_mode(vs, mode);
 
+    if (vs->vd->num_shared > vs->vd->connections_limit) {
+        vnc_disconnect_start(vs);
+        return 0;
+    }
+
     vs->client_width = pixman_image_get_width(vs->vd->server);
     vs->client_height = pixman_image_get_height(vs->vd->server);
     vnc_write_u16(vs, vs->client_width);
@@ -2889,6 +2916,15 @@ static void vnc_connect(VncDisplay *vd, int csock,
     {
         vnc_init_state(vs);
     }
+
+    if (vd->num_connecting > vd->connections_limit) {
+        QTAILQ_FOREACH(vs, &vd->clients, next) {
+            if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) {
+                vnc_disconnect_start(vs);
+                return;
+            }
+        }
+    }
 }
 
 void vnc_init_state(VncState *vs)
@@ -2907,7 +2943,7 @@ void vnc_init_state(VncState *vs)
     qemu_mutex_init(&vs->output_mutex);
     vs->bh = qemu_bh_new(vnc_jobs_bh, vs);
 
-    QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
+    QTAILQ_INSERT_TAIL(&vd->clients, vs, next);
 
     graphic_hw_update(vd->dcl.con);
 
@@ -3098,6 +3134,9 @@ static QemuOptsList qemu_vnc_opts = {
             .name = "head",
             .type = QEMU_OPT_NUMBER,
         },{
+            .name = "connections",
+            .type = QEMU_OPT_NUMBER,
+        },{
             .name = "password",
             .type = QEMU_OPT_BOOL,
         },{
@@ -3211,6 +3250,7 @@ void vnc_display_open(const char *id, Error **errp)
     } else {
         vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
     }
+    vs->connections_limit = qemu_opt_get_number(opts, "connections", 32);
 
  #ifdef CONFIG_VNC_WS
     websocket = qemu_opt_get(opts, "websocket");
diff --git a/ui/vnc.h b/ui/vnc.h
index 6fe8278..5e2b1a5 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -150,7 +150,10 @@ typedef enum VncSharePolicy {
 struct VncDisplay
 {
     QTAILQ_HEAD(, VncState) clients;
+    int num_connecting;
+    int num_shared;
     int num_exclusive;
+    int connections_limit;
     VncSharePolicy share_policy;
     int lsock;
 #ifdef CONFIG_VNC_WS
commit 86fdcf23f4a9d8473844734907555b3a93ed686c
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Oct 2 15:53:37 2014 +0200

    vnc: update docs/multiseat.txt
    
    vnc joins the party ;)
    Also some s/head/seat/ to clarify.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/docs/multiseat.txt b/docs/multiseat.txt
index 67151e0..b963665 100644
--- a/docs/multiseat.txt
+++ b/docs/multiseat.txt
@@ -7,7 +7,7 @@ host side
 
 First you must compile qemu with a user interface supporting
 multihead/multiseat and input event routing.  Right now this
-list includes sdl2 and gtk (both 2+3):
+list includes sdl2, gtk (both 2+3) and vnc:
 
   ./configure --enable-sdl --with-sdlabi=2.0
 
@@ -16,16 +16,16 @@ or
   ./configure --enable-gtk
 
 
-Next put together the qemu command line:
+Next put together the qemu command line (sdk/gtk):
 
 qemu	-enable-kvm -usb $memory $disk $whatever \
 	-display [ sdl | gtk ] \
 	-vga std \
 	-device usb-tablet
 
-That is it for the first head, which will use the standard vga, the
+That is it for the first seat, which will use the standard vga, the
 standard ps/2 keyboard (implicitly there) and the usb-tablet.  Now the
-additional switches for the second head:
+additional switches for the second seat:
 
 	-device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
 	-device secondary-vga,bus=head.2,addr=02.0,id=video.2 \
@@ -47,6 +47,16 @@ in a separate tab.  You can either simply switch tabs to switch heads,
 or use the "View / Detach tab" menu item to move one of the displays
 to its own window so you can see both display devices side-by-side.
 
+For vnc some additional configuration on the command line is needed.
+We'll create two vnc server instances, and bind the second one to the
+second seat, simliar to input devices:
+
+	-display vnc=:1,id=primary \
+	-display vnc=:2,id=secondary,display=video.2
+
+Connecting to vnc display :1 gives you access to the first seat, and
+likewise connecting to vnc display :2 shows the second seat.
+
 Note on spice: Spice handles multihead just fine.  But it can't do
 multiseat.  For tablet events the event source is sent to the spice
 agent.  But qemu can't figure it, so it can't do input routing.
commit 1d0d59fe291967533f974e82213656d479475a1e
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Sep 18 12:54:49 2014 +0200

    vnc: allow binding servers to qemu consoles
    
    This patch adds a display= parameter to the vnc options.  This allows to
    bind a vnc server instance to a specific display, allowing to create a
    multiseat setup with a vnc server for each seat.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index 24cf08b..091e809 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -27,6 +27,7 @@
 #include "vnc.h"
 #include "vnc-jobs.h"
 #include "trace.h"
+#include "hw/qdev.h"
 #include "sysemu/sysemu.h"
 #include "qemu/sockets.h"
 #include "qemu/timer.h"
@@ -1665,7 +1666,8 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
             vs->modifiers_state[keycode] = 0;
         break;
     case 0x02 ... 0x0a: /* '1' to '9' keys */
-        if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
+        if (vs->vd->dcl.con == NULL &&
+            down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
             /* Reset the modifiers sent to the current console */
             reset_keys(vs);
             console_select(keycode - 0x02);
@@ -2073,8 +2075,8 @@ static void set_pixel_format(VncState *vs,
 
     set_pixel_conversion(vs);
 
-    graphic_hw_invalidate(NULL);
-    graphic_hw_update(NULL);
+    graphic_hw_invalidate(vs->vd->dcl.con);
+    graphic_hw_update(vs->vd->dcl.con);
 }
 
 static void pixel_format_message (VncState *vs) {
@@ -2801,7 +2803,7 @@ static void vnc_refresh(DisplayChangeListener *dcl)
         return;
     }
 
-    graphic_hw_update(NULL);
+    graphic_hw_update(vd->dcl.con);
 
     if (vnc_trylock_display(vd)) {
         update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
@@ -2907,7 +2909,7 @@ void vnc_init_state(VncState *vs)
 
     QTAILQ_INSERT_HEAD(&vd->clients, vs, next);
 
-    graphic_hw_update(NULL);
+    graphic_hw_update(vd->dcl.con);
 
     vnc_write(vs, "RFB 003.008\n", 12);
     vnc_flush(vs);
@@ -2930,7 +2932,7 @@ static void vnc_listen_read(void *opaque, bool websocket)
     int csock;
 
     /* Catch-up */
-    graphic_hw_update(NULL);
+    graphic_hw_update(vs->dcl.con);
 #ifdef CONFIG_VNC_WS
     if (websocket) {
         csock = qemu_accept(vs->lwebsock, (struct sockaddr *)&addr, &addrlen);
@@ -3090,6 +3092,12 @@ static QemuOptsList qemu_vnc_opts = {
             .name = "share",
             .type = QEMU_OPT_STRING,
         },{
+            .name = "display",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "head",
+            .type = QEMU_OPT_NUMBER,
+        },{
             .name = "password",
             .type = QEMU_OPT_BOOL,
         },{
@@ -3125,7 +3133,8 @@ void vnc_display_open(const char *id, Error **errp)
 {
     VncDisplay *vs = vnc_display_find(id);
     QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
-    const char *display, *websocket, *share;
+    const char *display, *websocket, *share, *device_id;
+    QemuConsole *con;
     int password = 0;
     int reverse = 0;
 #ifdef CONFIG_VNC_TLS
@@ -3354,6 +3363,33 @@ void vnc_display_open(const char *id, Error **errp)
 #endif
     vs->lock_key_sync = lock_key_sync;
 
+    device_id = qemu_opt_get(opts, "display");
+    if (device_id) {
+        DeviceState *dev;
+        int head = qemu_opt_get_number(opts, "head", 0);
+
+        dev = qdev_find_recursive(sysbus_get_default(), device_id);
+        if (dev == NULL) {
+            error_set(errp, QERR_DEVICE_NOT_FOUND, device_id);
+            goto fail;
+        }
+
+        con = qemu_console_lookup_by_device(dev, head);
+        if (con == NULL) {
+            error_setg(errp, "Device %s is not bound to a QemuConsole",
+                       device_id);
+            goto fail;
+        }
+    } else {
+        con = NULL;
+    }
+
+    if (con != vs->dcl.con) {
+        unregister_displaychangelistener(&vs->dcl);
+        vs->dcl.con = con;
+        register_displaychangelistener(&vs->dcl);
+    }
+
     if (reverse) {
         /* connect to viewer */
         int csock;
commit 4db14629c38611061fc19ec6927405923de84f08
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Sep 16 12:33:03 2014 +0200

    vnc: switch to QemuOpts, allow multiple servers
    
    This patch switches vnc over to QemuOpts, and it (more or less
    as side effect) allows multiple vnc server instances.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/include/ui/console.h b/include/ui/console.h
index 03358b4..8a4d671 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -332,12 +332,14 @@ void cocoa_display_init(DisplayState *ds, int full_screen);
 
 /* vnc.c */
 void vnc_display_init(const char *id);
-void vnc_display_open(const char *id, const char *display, Error **errp);
+void vnc_display_open(const char *id, Error **errp);
 void vnc_display_add_client(const char *id, int csock, bool skipauth);
 char *vnc_display_local_addr(const char *id);
 #ifdef CONFIG_VNC
 int vnc_display_password(const char *id, const char *password);
 int vnc_display_pw_expire(const char *id, time_t expires);
+QemuOpts *vnc_parse_func(const char *str);
+int vnc_init_func(QemuOpts *opts, void *opaque);
 #else
 static inline int vnc_display_password(const char *id, const char *password)
 {
diff --git a/qmp.c b/qmp.c
index 0b4f131..963305c 100644
--- a/qmp.c
+++ b/qmp.c
@@ -368,7 +368,20 @@ void qmp_change_vnc_password(const char *password, Error **errp)
 
 static void qmp_change_vnc_listen(const char *target, Error **errp)
 {
-    vnc_display_open(NULL, target, errp);
+    QemuOptsList *olist = qemu_find_opts("vnc");
+    QemuOpts *opts;
+
+    if (strstr(target, "id=")) {
+        error_setg(errp, "id not supported");
+        return;
+    }
+
+    opts = qemu_opts_find(olist, "default");
+    if (opts) {
+        qemu_opts_del(opts);
+    }
+    opts = vnc_parse_func(target);
+    vnc_display_open("default", errp);
 }
 
 static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
diff --git a/ui/vnc.c b/ui/vnc.c
index 24b5540..24cf08b 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -31,6 +31,7 @@
 #include "qemu/sockets.h"
 #include "qemu/timer.h"
 #include "qemu/acl.h"
+#include "qemu/config-file.h"
 #include "qapi/qmp/types.h"
 #include "qmp-commands.h"
 #include "qemu/osdep.h"
@@ -2970,7 +2971,12 @@ static const DisplayChangeListenerOps dcl_ops = {
 
 void vnc_display_init(const char *id)
 {
-    VncDisplay *vs = g_malloc0(sizeof(*vs));
+    VncDisplay *vs;
+
+    if (vnc_display_find(id) != NULL) {
+        return;
+    }
+    vs = g_malloc0(sizeof(*vs));
 
     vs->id = strdup(id);
     QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
@@ -3066,14 +3072,65 @@ char *vnc_display_local_addr(const char *id)
     return vnc_socket_local_addr("%s:%s", vs->lsock);
 }
 
-void vnc_display_open(const char *id, const char *display, Error **errp)
+static QemuOptsList qemu_vnc_opts = {
+    .name = "vnc",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_vnc_opts.head),
+    .implied_opt_name = "vnc",
+    .desc = {
+        {
+            .name = "vnc",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "websocket",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "x509",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "share",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "password",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "reverse",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "lock-key-sync",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "sasl",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "tls",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "x509verify",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "acl",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "lossy",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "non-adaptive",
+            .type = QEMU_OPT_BOOL,
+        },
+        { /* end of list */ }
+    },
+};
+
+void vnc_display_open(const char *id, Error **errp)
 {
     VncDisplay *vs = vnc_display_find(id);
-    const char *options;
+    QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
+    const char *display, *websocket, *share;
     int password = 0;
     int reverse = 0;
 #ifdef CONFIG_VNC_TLS
     int tls = 0, x509 = 0;
+    const char *path;
 #endif
 #ifdef CONFIG_VNC_SASL
     int sasl = 0;
@@ -3089,115 +3146,86 @@ void vnc_display_open(const char *id, const char *display, Error **errp)
         return;
     }
     vnc_display_close(vs);
-    if (strcmp(display, "none") == 0)
-        return;
 
+    if (!opts) {
+        return;
+    }
+    display = qemu_opt_get(opts, "vnc");
+    if (!display || strcmp(display, "none") == 0) {
+        return;
+    }
     vs->display = g_strdup(display);
-    vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
-
-    options = display;
-    while ((options = strchr(options, ','))) {
-        options++;
-        if (strncmp(options, "password", 8) == 0) {
-            if (fips_get_state()) {
-                error_setg(errp,
-                           "VNC password auth disabled due to FIPS mode, "
-                           "consider using the VeNCrypt or SASL authentication "
-                           "methods as an alternative");
-                goto fail;
-            }
-            password = 1; /* Require password auth */
-        } else if (strncmp(options, "reverse", 7) == 0) {
-            reverse = 1;
-        } else if (strncmp(options, "no-lock-key-sync", 16) == 0) {
-            lock_key_sync = 0;
+
+    password = qemu_opt_get_bool(opts, "password", false);
+    if (password && fips_get_state()) {
+        error_setg(errp,
+                   "VNC password auth disabled due to FIPS mode, "
+                   "consider using the VeNCrypt or SASL authentication "
+                   "methods as an alternative");
+        goto fail;
+    }
+
+    reverse = qemu_opt_get_bool(opts, "reverse", false);
+    lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true);
 #ifdef CONFIG_VNC_SASL
-        } else if (strncmp(options, "sasl", 4) == 0) {
-            sasl = 1; /* Require SASL auth */
+    sasl = qemu_opt_get_bool(opts, "sasl", false);
 #endif
-#ifdef CONFIG_VNC_WS
-        } else if (strncmp(options, "websocket", 9) == 0) {
-            char *start, *end;
-            vs->websocket = 1;
-
-            /* Check for 'websocket=<port>' */
-            start = strchr(options, '=');
-            end = strchr(options, ',');
-            if (start && (!end || (start < end))) {
-                int len = end ? end-(start+1) : strlen(start+1);
-                if (len < 6) {
-                    /* extract the host specification from display */
-                    char  *host = NULL, *port = NULL, *host_end = NULL;
-                    port = g_strndup(start + 1, len);
-
-                    /* ipv6 hosts have colons */
-                    end = strchr(display, ',');
-                    host_end = g_strrstr_len(display, end - display, ":");
-
-                    if (host_end) {
-                        host = g_strndup(display, host_end - display + 1);
-                    } else {
-                        host = g_strndup(":", 1);
-                    }
-                    vs->ws_display = g_strconcat(host, port, NULL);
-                    g_free(host);
-                    g_free(port);
-                }
-            }
-#endif /* CONFIG_VNC_WS */
 #ifdef CONFIG_VNC_TLS
-        } else if (strncmp(options, "tls", 3) == 0) {
-            tls = 1; /* Require TLS */
-        } else if (strncmp(options, "x509", 4) == 0) {
-            char *start, *end;
-            x509 = 1; /* Require x509 certificates */
-            if (strncmp(options, "x509verify", 10) == 0)
-                vs->tls.x509verify = 1; /* ...and verify client certs */
-
-            /* Now check for 'x509=/some/path' postfix
-             * and use that to setup x509 certificate/key paths */
-            start = strchr(options, '=');
-            end = strchr(options, ',');
-            if (start && (!end || (start < end))) {
-                int len = end ? end-(start+1) : strlen(start+1);
-                char *path = g_strndup(start + 1, len);
-
-                VNC_DEBUG("Trying certificate path '%s'\n", path);
-                if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
-                    error_setg(errp, "Failed to find x509 certificates/keys in %s", path);
-                    g_free(path);
-                    goto fail;
-                }
-                g_free(path);
-            } else {
-                error_setg(errp, "No certificate path provided");
-                goto fail;
-            }
+    tls  = qemu_opt_get_bool(opts, "tls", false);
+    path = qemu_opt_get(opts, "x509");
+    if (path) {
+        x509 = 1;
+        vs->tls.x509verify = qemu_opt_get_bool(opts, "x509verify", false);
+        if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
+            error_setg(errp, "Failed to find x509 certificates/keys in %s",
+                       path);
+            goto fail;
+        }
+    }
 #endif
 #if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
-        } else if (strncmp(options, "acl", 3) == 0) {
-            acl = 1;
-#endif
-        } else if (strncmp(options, "lossy", 5) == 0) {
-#ifdef CONFIG_VNC_JPEG
-            vs->lossy = true;
+    acl = qemu_opt_get_bool(opts, "acl", false);
 #endif
-        } else if (strncmp(options, "non-adaptive", 12) == 0) {
-            vs->non_adaptive = true;
-        } else if (strncmp(options, "share=", 6) == 0) {
-            if (strncmp(options+6, "ignore", 6) == 0) {
-                vs->share_policy = VNC_SHARE_POLICY_IGNORE;
-            } else if (strncmp(options+6, "allow-exclusive", 15) == 0) {
-                vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
-            } else if (strncmp(options+6, "force-shared", 12) == 0) {
-                vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
-            } else {
-                error_setg(errp, "unknown vnc share= option");
-                goto fail;
-            }
+
+    share = qemu_opt_get(opts, "share");
+    if (share) {
+        if (strcmp(share, "ignore") == 0) {
+            vs->share_policy = VNC_SHARE_POLICY_IGNORE;
+        } else if (strcmp(share, "allow-exclusive") == 0) {
+            vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
+        } else if (strcmp(share, "force-shared") == 0) {
+            vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
+        } else {
+            error_setg(errp, "unknown vnc share= option");
+            goto fail;
+        }
+    } else {
+        vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
+    }
+
+ #ifdef CONFIG_VNC_WS
+    websocket = qemu_opt_get(opts, "websocket");
+    if (websocket) {
+        /* extract the host specification from display */
+        char  *host = NULL, *host_end = NULL;
+        vs->websocket = 1;
+
+        /* ipv6 hosts have colons */
+        host_end = strrchr(display, ':');
+        if (host_end) {
+            host = g_strndup(display, host_end - display + 1);
+        } else {
+            host = g_strdup(":");
         }
+        vs->ws_display = g_strconcat(host, websocket, NULL);
+        g_free(host);
     }
+#endif /* CONFIG_VNC_WS */
 
+#ifdef CONFIG_VNC_JPEG
+    vs->lossy = qemu_opt_get_bool(opts, "lossy", false);
+#endif
+    vs->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false);
     /* adaptive updates are only used with tight encoding and
      * if lossy updates are enabled so we can disable all the
      * calculations otherwise */
@@ -3408,3 +3436,43 @@ void vnc_display_add_client(const char *id, int csock, bool skipauth)
     }
     vnc_connect(vs, csock, skipauth, false);
 }
+
+QemuOpts *vnc_parse_func(const char *str)
+{
+    return qemu_opts_parse(qemu_find_opts("vnc"), str, 1);
+}
+
+int vnc_init_func(QemuOpts *opts, void *opaque)
+{
+    Error *local_err = NULL;
+    QemuOptsList *olist = qemu_find_opts("vnc");
+    char *id = (char *)qemu_opts_id(opts);
+
+    if (!id) {
+        /* auto-assign id if not present */
+        int i = 2;
+        id = g_strdup("default");
+        while (qemu_opts_find(olist, id)) {
+            g_free(id);
+            id = g_strdup_printf("vnc%d", i++);
+        }
+        qemu_opts_set_id(opts, id);
+    }
+
+    vnc_display_init(id);
+    vnc_display_open(id, &local_err);
+    if (local_err != NULL) {
+        error_report("Failed to start VNC server on `%s': %s",
+                     qemu_opt_get(opts, "display"),
+                     error_get_pretty(local_err));
+        error_free(local_err);
+        exit(1);
+    }
+    return 0;
+}
+
+static void vnc_register_config(void)
+{
+    qemu_add_opts(&qemu_vnc_opts);
+}
+machine_init(vnc_register_config);
diff --git a/vl.c b/vl.c
index 9fb32c1..983259b 100644
--- a/vl.c
+++ b/vl.c
@@ -158,9 +158,6 @@ int smp_cpus = 1;
 int max_cpus = 0;
 int smp_cores = 1;
 int smp_threads = 1;
-#ifdef CONFIG_VNC
-const char *vnc_display;
-#endif
 int acpi_enabled = 1;
 int no_hpet = 0;
 int fd_bootchk = 1;
@@ -2002,16 +1999,12 @@ static DisplayType select_display(const char *p)
 #endif
     } else if (strstart(p, "vnc", &opts)) {
 #ifdef CONFIG_VNC
-        display_remote++;
-
-        if (*opts) {
-            const char *nextopt;
-
-            if (strstart(opts, "=", &nextopt)) {
-                vnc_display = nextopt;
+        if (*opts == '=') {
+            display_remote++;
+            if (vnc_parse_func(opts+1) == NULL) {
+                exit(1);
             }
-        }
-        if (!vnc_display) {
+        } else {
             fprintf(stderr, "VNC requires a display argument vnc=<display>\n");
             exit(1);
         }
@@ -3479,7 +3472,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_vnc:
 #ifdef CONFIG_VNC
                 display_remote++;
-                vnc_display = optarg;
+                if (vnc_parse_func(optarg) == NULL) {
+                    exit(1);
+                }
 #else
                 fprintf(stderr, "VNC support is disabled\n");
                 exit(1);
@@ -3975,7 +3970,7 @@ int main(int argc, char **argv, char **envp)
 #elif defined(CONFIG_SDL) || defined(CONFIG_COCOA)
         display_type = DT_SDL;
 #elif defined(CONFIG_VNC)
-        vnc_display = "localhost:0,to=99";
+        vnc_parse_func("localhost:0,to=99,id=default");
         show_vnc_port = 1;
 #else
         display_type = DT_NONE;
@@ -4286,21 +4281,10 @@ int main(int argc, char **argv, char **envp)
 
 #ifdef CONFIG_VNC
     /* init remote displays */
-    if (vnc_display) {
-        Error *local_err = NULL;
-        const char *id = "default";
-        vnc_display_init(id);
-        vnc_display_open(id, vnc_display, &local_err);
-        if (local_err != NULL) {
-            error_report("Failed to start VNC server on `%s': %s",
-                         vnc_display, error_get_pretty(local_err));
-            error_free(local_err);
-            exit(1);
-        }
-
-        if (show_vnc_port) {
-            printf("VNC server running on `%s'\n", vnc_display_local_addr(id));
-        }
+    qemu_opts_foreach(qemu_find_opts("vnc"), vnc_init_func, NULL, 0);
+    if (show_vnc_port) {
+        printf("VNC server running on `%s'\n",
+               vnc_display_local_addr("default"));
     }
 #endif
 #ifdef CONFIG_SPICE
commit c8496408b443a2a34dd03ad4274c2575248aa3e8
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Oct 21 14:50:42 2014 +0200

    vnc: add display id to acl names
    
    In case the display id is "default" (which is the one you get if you
    don't explicitly assign one) we keep the old name scheme, without
    display, for backward compatibility reasons.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Reviewed-by: Gonglei <arei.gonglei at huawei.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index d988275..24b5540 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3207,18 +3207,36 @@ void vnc_display_open(const char *id, const char *display, Error **errp)
 
 #ifdef CONFIG_VNC_TLS
     if (acl && x509 && vs->tls.x509verify) {
-        if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) {
+        char *aclname;
+
+        if (strcmp(vs->id, "default") == 0) {
+            aclname = g_strdup("vnc.x509dname");
+        } else {
+            aclname = g_strdup_printf("vnc.%s.x509dname", vs->id);
+        }
+        vs->tls.acl = qemu_acl_init(aclname);
+        if (!vs->tls.acl) {
             fprintf(stderr, "Failed to create x509 dname ACL\n");
             exit(1);
         }
+        g_free(aclname);
     }
 #endif
 #ifdef CONFIG_VNC_SASL
     if (acl && sasl) {
-        if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) {
+        char *aclname;
+
+        if (strcmp(vs->id, "default") == 0) {
+            aclname = g_strdup("vnc.username");
+        } else {
+            aclname = g_strdup_printf("vnc.%s.username", vs->id);
+        }
+        vs->sasl.acl = qemu_acl_init(aclname);
+        if (!vs->sasl.acl) {
             fprintf(stderr, "Failed to create username ACL\n");
             exit(1);
         }
+        g_free(aclname);
     }
 #endif
 
commit 14f7143ede7c601cce02ce0f8c7f01c41148128b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jul 29 12:24:55 2014 +0200

    vnc: remove unused DisplayState parameter, add id instead.
    
    DisplayState isn't used anywhere, drop it.  Add the vnc server ID as
    parameter instead, so it is possible to specify the server instance.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Reviewed-by: Gonglei <arei.gonglei at huawei.com>

diff --git a/include/ui/console.h b/include/ui/console.h
index 047b6da..03358b4 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -331,19 +331,19 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
 void cocoa_display_init(DisplayState *ds, int full_screen);
 
 /* vnc.c */
-void vnc_display_init(DisplayState *ds);
-void vnc_display_open(DisplayState *ds, const char *display, Error **errp);
-void vnc_display_add_client(DisplayState *ds, int csock, bool skipauth);
-char *vnc_display_local_addr(DisplayState *ds);
+void vnc_display_init(const char *id);
+void vnc_display_open(const char *id, const char *display, Error **errp);
+void vnc_display_add_client(const char *id, int csock, bool skipauth);
+char *vnc_display_local_addr(const char *id);
 #ifdef CONFIG_VNC
-int vnc_display_password(DisplayState *ds, const char *password);
-int vnc_display_pw_expire(DisplayState *ds, time_t expires);
+int vnc_display_password(const char *id, const char *password);
+int vnc_display_pw_expire(const char *id, time_t expires);
 #else
-static inline int vnc_display_password(DisplayState *ds, const char *password)
+static inline int vnc_display_password(const char *id, const char *password)
 {
     return -ENODEV;
 }
-static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
+static inline int vnc_display_pw_expire(const char *id, time_t expires)
 {
     return -ENODEV;
 };
diff --git a/ui/vnc.c b/ui/vnc.c
index 27e4d26..d988275 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2968,10 +2968,11 @@ static const DisplayChangeListenerOps dcl_ops = {
     .dpy_cursor_define    = vnc_dpy_cursor_define,
 };
 
-void vnc_display_init(DisplayState *ds)
+void vnc_display_init(const char *id)
 {
     VncDisplay *vs = g_malloc0(sizeof(*vs));
 
+    vs->id = strdup(id);
     QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
 
     vs->lsock = -1;
@@ -3000,10 +3001,8 @@ void vnc_display_init(DisplayState *ds)
 }
 
 
-static void vnc_display_close(DisplayState *ds)
+static void vnc_display_close(VncDisplay *vs)
 {
-    VncDisplay *vs = vnc_display_find(NULL);
-
     if (!vs)
         return;
     g_free(vs->display);
@@ -3029,9 +3028,9 @@ static void vnc_display_close(DisplayState *ds)
 #endif
 }
 
-int vnc_display_password(DisplayState *ds, const char *password)
+int vnc_display_password(const char *id, const char *password)
 {
-    VncDisplay *vs = vnc_display_find(NULL);
+    VncDisplay *vs = vnc_display_find(id);
 
     if (!vs) {
         return -EINVAL;
@@ -3048,9 +3047,9 @@ int vnc_display_password(DisplayState *ds, const char *password)
     return 0;
 }
 
-int vnc_display_pw_expire(DisplayState *ds, time_t expires)
+int vnc_display_pw_expire(const char *id, time_t expires)
 {
-    VncDisplay *vs = vnc_display_find(NULL);
+    VncDisplay *vs = vnc_display_find(id);
 
     if (!vs) {
         return -EINVAL;
@@ -3060,16 +3059,16 @@ int vnc_display_pw_expire(DisplayState *ds, time_t expires)
     return 0;
 }
 
-char *vnc_display_local_addr(DisplayState *ds)
+char *vnc_display_local_addr(const char *id)
 {
-    VncDisplay *vs = vnc_display_find(NULL);
+    VncDisplay *vs = vnc_display_find(id);
 
     return vnc_socket_local_addr("%s:%s", vs->lsock);
 }
 
-void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
+void vnc_display_open(const char *id, const char *display, Error **errp)
 {
-    VncDisplay *vs = vnc_display_find(NULL);
+    VncDisplay *vs = vnc_display_find(id);
     const char *options;
     int password = 0;
     int reverse = 0;
@@ -3089,7 +3088,7 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
         error_setg(errp, "VNC display not active");
         return;
     }
-    vnc_display_close(ds);
+    vnc_display_close(vs);
     if (strcmp(display, "none") == 0)
         return;
 
@@ -3382,9 +3381,9 @@ fail:
 #endif /* CONFIG_VNC_WS */
 }
 
-void vnc_display_add_client(DisplayState *ds, int csock, bool skipauth)
+void vnc_display_add_client(const char *id, int csock, bool skipauth)
 {
-    VncDisplay *vs = vnc_display_find(NULL);
+    VncDisplay *vs = vnc_display_find(id);
 
     if (!vs) {
         return;
diff --git a/vl.c b/vl.c
index fbf4240..9fb32c1 100644
--- a/vl.c
+++ b/vl.c
@@ -4288,8 +4288,9 @@ int main(int argc, char **argv, char **envp)
     /* init remote displays */
     if (vnc_display) {
         Error *local_err = NULL;
-        vnc_display_init(ds);
-        vnc_display_open(ds, vnc_display, &local_err);
+        const char *id = "default";
+        vnc_display_init(id);
+        vnc_display_open(id, vnc_display, &local_err);
         if (local_err != NULL) {
             error_report("Failed to start VNC server on `%s': %s",
                          vnc_display, error_get_pretty(local_err));
@@ -4298,7 +4299,7 @@ int main(int argc, char **argv, char **envp)
         }
 
         if (show_vnc_port) {
-            printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
+            printf("VNC server running on `%s'\n", vnc_display_local_addr(id));
         }
     }
 #endif
commit d616ccc5dd771024e04b9b15d7ca30bc7fe8fce3
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Tue Jul 29 12:14:08 2014 +0200

    vnc: remove vnc_display global
    
    Replace with a vnc_displays list, so we can have multiple vnc server
    instances.  Add vnc_server_find function to lookup a display by id.
    With no id supplied return the first vnc server, for backward
    compatibility reasons.
    
    It is not possible (yet) to actually create multiple vnc server
    instances.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
    Reviewed-by: Gonglei <arei.gonglei at huawei.com>

diff --git a/ui/vnc.c b/ui/vnc.c
index 0385160..27e4d26 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -46,7 +46,8 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
 #include "vnc_keysym.h"
 #include "d3des.h"
 
-static VncDisplay *vnc_display; /* needed for info vnc */
+static QTAILQ_HEAD(, VncDisplay) vnc_displays =
+    QTAILQ_HEAD_INITIALIZER(vnc_displays);
 
 static int vnc_cursor_define(VncState *vs);
 static void vnc_release_modifiers(VncState *vs);
@@ -226,10 +227,10 @@ static const char *vnc_auth_name(VncDisplay *vd) {
     return "unknown";
 }
 
-static VncServerInfo *vnc_server_info_get(void)
+static VncServerInfo *vnc_server_info_get(VncDisplay *vd)
 {
     VncServerInfo *info;
-    VncBasicInfo *bi = vnc_basic_info_get_from_server_addr(vnc_display->lsock);
+    VncBasicInfo *bi = vnc_basic_info_get_from_server_addr(vd->lsock);
     if (!bi) {
         return NULL;
     }
@@ -237,7 +238,7 @@ static VncServerInfo *vnc_server_info_get(void)
     info = g_malloc(sizeof(*info));
     info->base = bi;
     info->has_auth = true;
-    info->auth = g_strdup(vnc_auth_name(vnc_display));
+    info->auth = g_strdup(vnc_auth_name(vd));
     return info;
 }
 
@@ -282,7 +283,7 @@ static void vnc_qmp_event(VncState *vs, QAPIEvent event)
     }
     g_assert(vs->info->base);
 
-    si = vnc_server_info_get();
+    si = vnc_server_info_get(vs->vd);
     if (!si) {
         return;
     }
@@ -345,11 +346,27 @@ static VncClientInfo *qmp_query_vnc_client(const VncState *client)
     return info;
 }
 
+static VncDisplay *vnc_display_find(const char *id)
+{
+    VncDisplay *vd;
+
+    if (id == NULL) {
+        return QTAILQ_FIRST(&vnc_displays);
+    }
+    QTAILQ_FOREACH(vd, &vnc_displays, next) {
+        if (strcmp(id, vd->id) == 0) {
+            return vd;
+        }
+    }
+    return NULL;
+}
+
 VncInfo *qmp_query_vnc(Error **errp)
 {
     VncInfo *info = g_malloc0(sizeof(*info));
+    VncDisplay *vd = vnc_display_find(NULL);
 
-    if (vnc_display == NULL || vnc_display->display == NULL) {
+    if (vd == NULL || vd->display == NULL) {
         info->enabled = false;
     } else {
         VncClientInfoList *cur_item = NULL;
@@ -364,7 +381,7 @@ VncInfo *qmp_query_vnc(Error **errp)
         /* for compatibility with the original command */
         info->has_clients = true;
 
-        QTAILQ_FOREACH(client, &vnc_display->clients, next) {
+        QTAILQ_FOREACH(client, &vd->clients, next) {
             VncClientInfoList *cinfo = g_malloc0(sizeof(*info));
             cinfo->value = qmp_query_vnc_client(client);
 
@@ -377,11 +394,11 @@ VncInfo *qmp_query_vnc(Error **errp)
             }
         }
 
-        if (vnc_display->lsock == -1) {
+        if (vd->lsock == -1) {
             return info;
         }
 
-        if (getsockname(vnc_display->lsock, (struct sockaddr *)&sa,
+        if (getsockname(vd->lsock, (struct sockaddr *)&sa,
                         &salen) == -1) {
             error_set(errp, QERR_UNDEFINED_ERROR);
             goto out_error;
@@ -405,7 +422,7 @@ VncInfo *qmp_query_vnc(Error **errp)
         info->family = inet_netfamily(sa.ss_family);
 
         info->has_auth = true;
-        info->auth = g_strdup(vnc_auth_name(vnc_display));
+        info->auth = g_strdup(vnc_auth_name(vd));
     }
 
     return info;
@@ -853,7 +870,7 @@ static int vnc_cursor_define(VncState *vs)
 static void vnc_dpy_cursor_define(DisplayChangeListener *dcl,
                                   QEMUCursor *c)
 {
-    VncDisplay *vd = vnc_display;
+    VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
     VncState *vs;
 
     cursor_put(vd->cursor);
@@ -2818,6 +2835,7 @@ static void vnc_connect(VncDisplay *vd, int csock,
     int i;
 
     vs->csock = csock;
+    vs->vd = vd;
 
     if (skipauth) {
 	vs->auth = VNC_AUTH_NONE;
@@ -2862,8 +2880,6 @@ static void vnc_connect(VncDisplay *vd, int csock,
     vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED);
     vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
 
-    vs->vd = vd;
-
 #ifdef CONFIG_VNC_WS
     if (!vs->websocket)
 #endif
@@ -2956,7 +2972,7 @@ void vnc_display_init(DisplayState *ds)
 {
     VncDisplay *vs = g_malloc0(sizeof(*vs));
 
-    vnc_display = vs;
+    QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
 
     vs->lsock = -1;
 #ifdef CONFIG_VNC_WS
@@ -2986,7 +3002,7 @@ void vnc_display_init(DisplayState *ds)
 
 static void vnc_display_close(DisplayState *ds)
 {
-    VncDisplay *vs = vnc_display;
+    VncDisplay *vs = vnc_display_find(NULL);
 
     if (!vs)
         return;
@@ -3015,7 +3031,7 @@ static void vnc_display_close(DisplayState *ds)
 
 int vnc_display_password(DisplayState *ds, const char *password)
 {
-    VncDisplay *vs = vnc_display;
+    VncDisplay *vs = vnc_display_find(NULL);
 
     if (!vs) {
         return -EINVAL;
@@ -3034,7 +3050,7 @@ int vnc_display_password(DisplayState *ds, const char *password)
 
 int vnc_display_pw_expire(DisplayState *ds, time_t expires)
 {
-    VncDisplay *vs = vnc_display;
+    VncDisplay *vs = vnc_display_find(NULL);
 
     if (!vs) {
         return -EINVAL;
@@ -3046,14 +3062,14 @@ int vnc_display_pw_expire(DisplayState *ds, time_t expires)
 
 char *vnc_display_local_addr(DisplayState *ds)
 {
-    VncDisplay *vs = vnc_display;
-    
+    VncDisplay *vs = vnc_display_find(NULL);
+
     return vnc_socket_local_addr("%s:%s", vs->lsock);
 }
 
 void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
 {
-    VncDisplay *vs = vnc_display;
+    VncDisplay *vs = vnc_display_find(NULL);
     const char *options;
     int password = 0;
     int reverse = 0;
@@ -3069,7 +3085,7 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp)
 #endif
     int lock_key_sync = 1;
 
-    if (!vnc_display) {
+    if (!vs) {
         error_setg(errp, "VNC display not active");
         return;
     }
@@ -3368,7 +3384,10 @@ fail:
 
 void vnc_display_add_client(DisplayState *ds, int csock, bool skipauth)
 {
-    VncDisplay *vs = vnc_display;
+    VncDisplay *vs = vnc_display_find(NULL);
 
+    if (!vs) {
+        return;
+    }
     vnc_connect(vs, csock, skipauth, false);
 }
diff --git a/ui/vnc.h b/ui/vnc.h
index 334de9d..6fe8278 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -171,6 +171,8 @@ struct VncDisplay
     struct VncSurface guest;   /* guest visible surface (aka ds->surface) */
     pixman_image_t *server;    /* vnc server surface */
 
+    const char *id;
+    QTAILQ_ENTRY(VncDisplay) next;
     char *display;
     char *password;
     time_t expires;
commit 51a090991449c7d3c6d428eda18b4f30a36e2c1b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jan 15 12:06:16 2015 +0100

    spice: fix coverity reported defect in display code
    
    Report:
    
    1. Condition surface, taking false branch
    406    if (surface && ssd->surface &&
    407        surface_width(surface) == pixman_image_get_width(ssd->surface) &&
    408        surface_height(surface) == pixman_image_get_height(ssd->surface)) {
    409        /* no-resize fast path: just swap backing store */
    ...
    
    10. alias_transfer: Assigning: ssd->ds = surface.
    440    ssd->ds = surface;
    
    11. var_deref_op: Dereferencing null pointer ssd->ds.
    CID 1264334 (#1 of 1): Dereference after null check (FORWARD_NULL)
    441    ssd->surface = pixman_image_ref(ssd->ds->image);
    
    Fix:
    
    Move code block dereferencing ssd->ds into the already existing
    if (ssd->ds) { ... } block.
    
    Cc: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/ui/spice-display.c b/ui/spice-display.c
index 8c87212..1644185 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -438,9 +438,6 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd,
     qemu_mutex_lock(&ssd->lock);
     need_destroy = (ssd->ds != NULL);
     ssd->ds = surface;
-    ssd->surface = pixman_image_ref(ssd->ds->image);
-    ssd->mirror  = qemu_pixman_mirror_create(ssd->ds->format,
-                                             ssd->ds->image);
     while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) {
         QTAILQ_REMOVE(&ssd->updates, update, next);
         qemu_spice_destroy_update(ssd, update);
@@ -450,6 +447,9 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd,
         qemu_spice_destroy_host_primary(ssd);
     }
     if (ssd->ds) {
+        ssd->surface = pixman_image_ref(ssd->ds->image);
+        ssd->mirror  = qemu_pixman_mirror_create(ssd->ds->format,
+                                                 ssd->ds->image);
         qemu_spice_create_host_primary(ssd);
     }
 
commit fe4831b1e7e7007ae15ae0470a06898660ab3877
Author: Marc-André Lureau <marcandre.lureau at gmail.com>
Date:   Tue Jan 13 17:57:51 2015 +0100

    spice: add unix address support
    
    Teach qemu to set up a Spice server with a UNIX socket using the
    following arguments -spice unix,addr=path.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qemu-options.hx b/qemu-options.hx
index 10b9568..85ca3ad 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -953,7 +953,7 @@ DEF("spice", HAS_ARG, QEMU_OPTION_spice,
     "-spice [port=port][,tls-port=secured-port][,x509-dir=<dir>]\n"
     "       [,x509-key-file=<file>][,x509-key-password=<file>]\n"
     "       [,x509-cert-file=<file>][,x509-cacert-file=<file>]\n"
-    "       [,x509-dh-key-file=<file>][,addr=addr][,ipv4|ipv6]\n"
+    "       [,x509-dh-key-file=<file>][,addr=addr][,ipv4|ipv6|unix]\n"
     "       [,tls-ciphers=<list>]\n"
     "       [,tls-channel=[main|display|cursor|inputs|record|playback]]\n"
     "       [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n"
@@ -982,6 +982,7 @@ Set the IP address spice is listening on.  Default is any address.
 
 @item ipv4
 @item ipv6
+ at item unix
 Force using the specified IP version.
 
 @item password=<secret>
diff --git a/ui/spice-core.c b/ui/spice-core.c
index fe705c1..c8f7f18 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -436,6 +436,11 @@ static QemuOptsList qemu_spice_opts = {
         },{
             .name = "ipv6",
             .type = QEMU_OPT_BOOL,
+#ifdef SPICE_ADDR_FLAG_UNIX_ONLY
+        },{
+            .name = "unix",
+            .type = QEMU_OPT_BOOL,
+#endif
         },{
             .name = "password",
             .type = QEMU_OPT_STRING,
@@ -708,6 +713,10 @@ void qemu_spice_init(void)
         addr_flags |= SPICE_ADDR_FLAG_IPV4_ONLY;
     } else if (qemu_opt_get_bool(opts, "ipv6", 0)) {
         addr_flags |= SPICE_ADDR_FLAG_IPV6_ONLY;
+#ifdef SPICE_ADDR_FLAG_UNIX_ONLY
+    } else if (qemu_opt_get_bool(opts, "unix", 0)) {
+        addr_flags |= SPICE_ADDR_FLAG_UNIX_ONLY;
+#endif
     }
 
     spice_server = spice_server_new();
commit 7230818a2b54df826e5ecdd83bd20632c9a8b07c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 23 22:11:21 2014 +0000

    disas/sparc: Remove unused data sparc_opcode_archs[]
    
    Remove sparc_opcode_archs and the macros which use it, because we don't
    use them in QEMU and they provoke clang warnings:
    
    disas/sparc.c:307:39: warning: unused variable 'sparc_opcode_archs' [-Wunused-const-variable]
    static const struct sparc_opcode_arch sparc_opcode_archs[] =
                                          ^
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>

diff --git a/disas/sparc.c b/disas/sparc.c
index 8e755d1..f4e3565 100644
--- a/disas/sparc.c
+++ b/disas/sparc.c
@@ -80,19 +80,6 @@ typedef struct sparc_opcode_arch
   short supported;
 } sparc_opcode_arch;
 
-static const struct sparc_opcode_arch sparc_opcode_archs[];
-
-/* Return the bitmask of supported architectures for ARCH.  */
-#define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported)
-
-/* Non-zero if ARCH1 conflicts with ARCH2.
-   IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa.  */
-#define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \
- (((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \
-   != SPARC_OPCODE_SUPPORTED (ARCH1)) \
-  && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \
-     != SPARC_OPCODE_SUPPORTED (ARCH2)))
-
 /* Structure of an opcode table entry.  */
 
 typedef struct sparc_opcode
@@ -301,25 +288,6 @@ static const char *sparc_decode_sparclet_cpreg (int);
    otherwise.  */
 #define v9notv9a        (MASK_V9)
 
-/* Table of opcode architectures.
-   The order is defined in opcode/sparc.h.  */
-
-static const struct sparc_opcode_arch sparc_opcode_archs[] =
-{
-  { "v6", MASK_V6 },
-  { "v7", MASK_V6 | MASK_V7 },
-  { "v8", MASK_V6 | MASK_V7 | MASK_V8 },
-  { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET },
-  { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE },
-  /* ??? Don't some v8 privileged insns conflict with v9?  */
-  { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 },
-  /* v9 with ultrasparc additions */
-  { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A },
-  /* v9 with cheetah additions */
-  { "v9b", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A | MASK_V9B },
-  { NULL, 0 }
-};
-
 /* Branch condition field.  */
 #define COND(x)         (((x) & 0xf) << 25)
 
commit a2035e83fd60e5b66644d321816ed634b908b4ee
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 23 22:11:20 2014 +0000

    target-sparc: Mark gen_load_trap_state_at_tl() as !CONFIG_USER_ONLY
    
    The function gen_load_trap_state_at_tl() is only used in the softmmu
    configs; wrap it in #ifndef CONFIG_USER_ONLY to avoid clang compiler
    warnings in linux-user builds.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 834b50f..68527d5 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2300,6 +2300,7 @@ static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs)
     gen_update_fprs_dirty(qd);
 }
 
+#ifndef CONFIG_USER_ONLY
 static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env)
 {
     TCGv_i32 r_tl = tcg_temp_new_i32();
@@ -2324,6 +2325,7 @@ static inline void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr, TCGv_ptr cpu_env)
 
     tcg_temp_free_i32(r_tl);
 }
+#endif
 
 static void gen_edge(DisasContext *dc, TCGv dst, TCGv s1, TCGv s2,
                      int width, bool cc, bool left)
commit 69694625e86aebb135b56c4aaafefd5c1d17bb3c
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 23 22:11:19 2014 +0000

    target-sparc: is_translating_asi() is TARGET_SPARC64 only
    
    Move the is_translating_asi() inside the TARGET_SPARC64 ifdef (and remove
    the unimplemented 32-bit codepath), as it is only called from TARGET_SPARC64
    code. This fixes a clang 3.4 unused-function warning.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>

diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index cdc21d3..c7ad47d 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -262,11 +262,12 @@ static inline target_ulong address_mask(CPUSPARCState *env1, target_ulong addr)
 }
 #endif
 
+#ifdef TARGET_SPARC64
 /* returns true if access using this ASI is to have address translated by MMU
    otherwise access is to raw physical address */
+/* TODO: check sparc32 bits */
 static inline int is_translating_asi(int asi)
 {
-#ifdef TARGET_SPARC64
     /* Ultrasparc IIi translating asi
        - note this list is defined by cpu implementation
     */
@@ -283,13 +284,8 @@ static inline int is_translating_asi(int asi)
     default:
         return 0;
     }
-#else
-    /* TODO: check sparc32 bits */
-    return 0;
-#endif
 }
 
-#ifdef TARGET_SPARC64
 static inline target_ulong asi_address_mask(CPUSPARCState *env,
                                             int asi, target_ulong addr)
 {
commit e60538c79fc7285e72f5b431281986737db1607b
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 23 22:11:18 2014 +0000

    target-sparc: address_mask(), asi_address_mask() are TARGET_SPARC64 only
    
    The address_mask() and asi_address_mask() functions are only used in
    TARGET_SPARC64 configs, so guard with ifdefs to avoid warnings about
    unused functions in 32-bit builds.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>

diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index e62228c..cdc21d3 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -250,6 +250,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
 
 #endif
 
+#if defined(TARGET_SPARC64) || defined(CONFIG_USER_ONLY)
 static inline target_ulong address_mask(CPUSPARCState *env1, target_ulong addr)
 {
 #ifdef TARGET_SPARC64
@@ -259,6 +260,7 @@ static inline target_ulong address_mask(CPUSPARCState *env1, target_ulong addr)
 #endif
     return addr;
 }
+#endif
 
 /* returns true if access using this ASI is to have address translated by MMU
    otherwise access is to raw physical address */
@@ -287,6 +289,7 @@ static inline int is_translating_asi(int asi)
 #endif
 }
 
+#ifdef TARGET_SPARC64
 static inline target_ulong asi_address_mask(CPUSPARCState *env,
                                             int asi, target_ulong addr)
 {
@@ -296,6 +299,7 @@ static inline target_ulong asi_address_mask(CPUSPARCState *env,
         return addr;
     }
 }
+#endif
 
 void helper_check_align(CPUSPARCState *env, target_ulong addr, uint32_t align)
 {
commit 622302901065ebcb21201310d34b22d107fe851e
Author: Peter Maydell <peter.maydell at linaro.org>
Date:   Tue Dec 23 22:11:17 2014 +0000

    target-sparc: Remove unused gen_op_subi_cc and gen_op_addi_cc
    
    The functions gen_op_addi_cc() and gen_op_subi_cc() are unused; remove them.
    
    Signed-off-by: Peter Maydell <peter.maydell at linaro.org>
    Reviewed-by: Richard Henderson <rth at twiddle.net>
    Signed-off-by: Mark Cave-Ayland <mark.cave-ayland at ilande.co.uk>

diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 25d1bd6..834b50f 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -363,14 +363,6 @@ static inline void gen_mov_reg_C(TCGv reg, TCGv_i32 src)
     tcg_gen_andi_tl(reg, reg, 0x1);
 }
 
-static inline void gen_op_addi_cc(TCGv dst, TCGv src1, target_long src2)
-{
-    tcg_gen_mov_tl(cpu_cc_src, src1);
-    tcg_gen_movi_tl(cpu_cc_src2, src2);
-    tcg_gen_addi_tl(cpu_cc_dst, cpu_cc_src, src2);
-    tcg_gen_mov_tl(dst, cpu_cc_dst);
-}
-
 static inline void gen_op_add_cc(TCGv dst, TCGv src1, TCGv src2)
 {
     tcg_gen_mov_tl(cpu_cc_src, src1);
@@ -502,22 +494,6 @@ static void gen_op_addx_int(DisasContext *dc, TCGv dst, TCGv src1,
     }
 }
 
-static inline void gen_op_subi_cc(TCGv dst, TCGv src1, target_long src2, DisasContext *dc)
-{
-    tcg_gen_mov_tl(cpu_cc_src, src1);
-    tcg_gen_movi_tl(cpu_cc_src2, src2);
-    if (src2 == 0) {
-        tcg_gen_mov_tl(cpu_cc_dst, src1);
-        tcg_gen_movi_i32(cpu_cc_op, CC_OP_LOGIC);
-        dc->cc_op = CC_OP_LOGIC;
-    } else {
-        tcg_gen_subi_tl(cpu_cc_dst, cpu_cc_src, src2);
-        tcg_gen_movi_i32(cpu_cc_op, CC_OP_SUB);
-        dc->cc_op = CC_OP_SUB;
-    }
-    tcg_gen_mov_tl(dst, cpu_cc_dst);
-}
-
 static inline void gen_op_sub_cc(TCGv dst, TCGv src1, TCGv src2)
 {
     tcg_gen_mov_tl(cpu_cc_src, src1);


More information about the Spice-commits mailing list