From patchwork Mon Jun 18 16:17:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931024 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418bqv4ZWnz9s1R for ; Tue, 19 Jun 2018 02:18:35 +1000 (AEST) Received: from localhost ([::1]:35729 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrR-0001lC-3s for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:18:33 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43736) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqc-0001jc-DN for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqX-0004u3-43 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:41 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45450 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqW-0004tj-VS for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:37 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7EB557DAC3 for ; Mon, 18 Jun 2018 16:17:36 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 905347C39; Mon, 18 Jun 2018 16:17:31 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:04 +0200 Message-Id: <20180618161729.334-2-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:17:36 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:17:36 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 01/26] chardev: avoid crash if no associated address X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" A socket chardev may not have associated address (when adding client fd manually for example). But on disconnect, updating socket filename expects an address and may lead to this crash: Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault. 0x0000555555d8c70c in SocketAddress_to_str (prefix=0x555556043062 "disconnected:", addr=0x0, is_listen=false, is_telnet=false) at /home/elmarco/src/qq/chardev/char-socket.c:388 388 switch (addr->type) { (gdb) bt #0 0x0000555555d8c70c in SocketAddress_to_str (prefix=0x555556043062 "disconnected:", addr=0x0, is_listen=false, is_telnet=false) at /home/elmarco/src/qq/chardev/char-socket.c:388 #1 0x0000555555d8c8aa in update_disconnected_filename (s=0x555556b1ed00) at /home/elmarco/src/qq/chardev/char-socket.c:419 #2 0x0000555555d8c959 in tcp_chr_disconnect (chr=0x555556b1ed00) at /home/elmarco/src/qq/chardev/char-socket.c:438 #3 0x0000555555d8cba1 in tcp_chr_hup (channel=0x555556b75690, cond=G_IO_HUP, opaque=0x555556b1ed00) at /home/elmarco/src/qq/chardev/char-socket.c:482 #4 0x0000555555da596e in qio_channel_fd_source_dispatch (source=0x555556bb68b0, callback=0x555555d8cb58 , user_data=0x555556b1ed00) at /home/elmarco/src/qq/io/channel-watch.c:84 Replace filename with a generic "disconnected:socket" in this case. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- chardev/char-socket.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 159e69c3b1..2a33079f8e 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -416,8 +416,12 @@ static void update_disconnected_filename(SocketChardev *s) Chardev *chr = CHARDEV(s); g_free(chr->filename); - chr->filename = SocketAddress_to_str("disconnected:", s->addr, - s->is_listen, s->is_telnet); + if (s->addr) { + chr->filename = SocketAddress_to_str("disconnected:", s->addr, + s->is_listen, s->is_telnet); + } else { + chr->filename = g_strdup("disconnected:socket"); + } } /* NB may be called even if tcp_chr_connect has not been From patchwork Mon Jun 18 16:17:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931028 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418bvd5st9z9s31 for ; Tue, 19 Jun 2018 02:21:49 +1000 (AEST) Received: from localhost ([::1]:35747 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwuZ-0004Kb-Du for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:21:47 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43734) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqc-0001jb-DL for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqZ-0004uh-SO for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:41 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40930 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqZ-0004ub-N4 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:39 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5ADA181A4E99 for ; Mon, 18 Jun 2018 16:17:39 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0FE817C39; Mon, 18 Jun 2018 16:17:38 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:06 +0200 Message-Id: <20180618161729.334-4-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:17:39 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:17:39 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 03/26] dmabuf: add y0_top, pass it to spice X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Some scanouts during boot are top-down without this. Signed-off-by: Marc-André Lureau --- include/ui/console.h | 1 + ui/spice-display.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/ui/console.h b/include/ui/console.h index 981b519dde..fb969caf70 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -186,6 +186,7 @@ struct QemuDmaBuf { uint32_t stride; uint32_t fourcc; uint32_t texture; + bool y0_top; }; typedef struct DisplayChangeListenerOps { diff --git a/ui/spice-display.c b/ui/spice-display.c index fe734821dd..81f08a85bc 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -1048,7 +1048,8 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl, /* note: spice server will close the fd, so hand over a dup */ spice_qxl_gl_scanout(&ssd->qxl, dup(dmabuf->fd), dmabuf->width, dmabuf->height, - dmabuf->stride, dmabuf->fourcc, false); + dmabuf->stride, dmabuf->fourcc, + dmabuf->y0_top); } qemu_spice_gl_monitor_config(ssd, 0, 0, dmabuf->width, dmabuf->height); ssd->guest_dmabuf_refresh = false; From patchwork Mon Jun 18 16:17:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931043 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418c2W3zFbz9s1R for ; Tue, 19 Jun 2018 02:27:47 +1000 (AEST) Received: from localhost ([::1]:35781 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx0J-0000gN-DR for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:27:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43795) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqh-0001nG-Bk for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqf-0004y0-P2 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:47 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57708 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqf-0004xg-If for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:45 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 356454000B74 for ; Mon, 18 Jun 2018 16:17:45 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7A7CD111DCEF; Mon, 18 Jun 2018 16:17:40 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:07 +0200 Message-Id: <20180618161729.334-5-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 18 Jun 2018 16:17:45 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 18 Jun 2018 16:17:45 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 04/26] vhost-user: simplify vhost_user_init/vhost_user_cleanup X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Take a VhostUserState* that can be pre-allocated, and initialize it with the associated chardev. Signed-off-by: Marc-André Lureau --- include/hw/virtio/vhost-user-blk.h | 2 +- include/hw/virtio/vhost-user-scsi.h | 2 +- include/hw/virtio/vhost-user.h | 2 +- backends/cryptodev-vhost-user.c | 18 ++++-------------- hw/block/vhost-user-blk.c | 22 ++++------------------ hw/scsi/vhost-user-scsi.c | 20 ++++---------------- hw/virtio/vhost-stub.c | 2 +- hw/virtio/vhost-user.c | 16 ++++++++++++---- net/vhost-user.c | 8 ++++---- 9 files changed, 32 insertions(+), 60 deletions(-) diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h index d52944aeeb..a8a106eecb 100644 --- a/include/hw/virtio/vhost-user-blk.h +++ b/include/hw/virtio/vhost-user-blk.h @@ -36,7 +36,7 @@ typedef struct VHostUserBlk { uint32_t queue_size; uint32_t config_wce; struct vhost_dev dev; - VhostUserState *vhost_user; + VhostUserState vhost_user; } VHostUserBlk; #endif diff --git a/include/hw/virtio/vhost-user-scsi.h b/include/hw/virtio/vhost-user-scsi.h index 3ec34ae867..7c22bdc957 100644 --- a/include/hw/virtio/vhost-user-scsi.h +++ b/include/hw/virtio/vhost-user-scsi.h @@ -31,7 +31,7 @@ typedef struct VHostUserSCSI { VHostSCSICommon parent_obj; uint64_t host_features; - VhostUserState *vhost_user; + VhostUserState vhost_user; } VHostUserSCSI; #endif /* VHOST_USER_SCSI_H */ diff --git a/include/hw/virtio/vhost-user.h b/include/hw/virtio/vhost-user.h index fd660393a0..811e325f42 100644 --- a/include/hw/virtio/vhost-user.h +++ b/include/hw/virtio/vhost-user.h @@ -22,7 +22,7 @@ typedef struct VhostUserState { VhostUserHostNotifier notifier[VIRTIO_QUEUE_MAX]; } VhostUserState; -VhostUserState *vhost_user_init(void); +bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp); void vhost_user_cleanup(VhostUserState *user); #endif diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c index d52daccfcd..63573e211e 100644 --- a/backends/cryptodev-vhost-user.c +++ b/backends/cryptodev-vhost-user.c @@ -47,7 +47,7 @@ typedef struct CryptoDevBackendVhostUser { CryptoDevBackend parent_obj; - VhostUserState *vhost_user; + VhostUserState vhost_user; CharBackend chr; char *chr_name; bool opened; @@ -104,7 +104,7 @@ cryptodev_vhost_user_start(int queues, continue; } - options.opaque = s->vhost_user; + options.opaque = &s->vhost_user; options.backend_type = VHOST_BACKEND_TYPE_USER; options.cc = b->conf.peers.ccs[i]; s->vhost_crypto[i] = cryptodev_vhost_init(&options); @@ -187,7 +187,6 @@ static void cryptodev_vhost_user_init( size_t i; Error *local_err = NULL; Chardev *chr; - VhostUserState *user; CryptoDevBackendClient *cc; CryptoDevBackendVhostUser *s = CRYPTODEV_BACKEND_VHOST_USER(backend); @@ -218,15 +217,10 @@ static void cryptodev_vhost_user_init( } } - user = vhost_user_init(); - if (!user) { - error_setg(errp, "Failed to init vhost_user"); + if (!vhost_user_init(&s->vhost_user, &s->chr, errp)) { return; } - user->chr = &s->chr; - s->vhost_user = user; - qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, cryptodev_vhost_user_event, NULL, s, NULL, true); @@ -312,11 +306,7 @@ static void cryptodev_vhost_user_cleanup( } } - if (s->vhost_user) { - vhost_user_cleanup(s->vhost_user); - g_free(s->vhost_user); - s->vhost_user = NULL; - } + vhost_user_cleanup(&s->vhost_user); } static void cryptodev_vhost_user_set_chardev(Object *obj, diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index d755223643..5a2c6fe5f3 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -224,7 +224,6 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostUserBlk *s = VHOST_USER_BLK(vdev); - VhostUserState *user; int i, ret; if (!s->chardev.chr) { @@ -242,15 +241,10 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) return; } - user = vhost_user_init(); - if (!user) { - error_setg(errp, "vhost-user-blk: failed to init vhost_user"); + if (!vhost_user_init(&s->vhost_user, &s->chardev, errp)) { return; } - user->chr = &s->chardev; - s->vhost_user = user; - virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, sizeof(struct virtio_blk_config)); @@ -266,7 +260,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) vhost_dev_set_config_notifier(&s->dev, &blk_ops); - ret = vhost_dev_init(&s->dev, s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); + ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); if (ret < 0) { error_setg(errp, "vhost-user-blk: vhost initialization failed: %s", strerror(-ret)); @@ -291,10 +285,7 @@ vhost_err: virtio_err: g_free(s->dev.vqs); virtio_cleanup(vdev); - - vhost_user_cleanup(user); - g_free(user); - s->vhost_user = NULL; + vhost_user_cleanup(&s->vhost_user); } static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) @@ -306,12 +297,7 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) vhost_dev_cleanup(&s->dev); g_free(s->dev.vqs); virtio_cleanup(vdev); - - if (s->vhost_user) { - vhost_user_cleanup(s->vhost_user); - g_free(s->vhost_user); - s->vhost_user = NULL; - } + vhost_user_cleanup(&s->vhost_user); } static void vhost_user_blk_instance_init(Object *obj) diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 9355cfdf07..b620725bc2 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -69,7 +69,6 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); VHostUserSCSI *s = VHOST_USER_SCSI(dev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); - VhostUserState *user; Error *err = NULL; int ret; @@ -86,30 +85,24 @@ static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) return; } - user = vhost_user_init(); - if (!user) { - error_setg(errp, "vhost-user-scsi: failed to init vhost_user"); + if (!vhost_user_init(&s->vhost_user, &vs->conf.chardev, errp)) { return; } - user->chr = &vs->conf.chardev; vsc->dev.nvqs = 2 + vs->conf.num_queues; vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs); vsc->dev.vq_index = 0; vsc->dev.backend_features = 0; - ret = vhost_dev_init(&vsc->dev, user, + ret = vhost_dev_init(&vsc->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); if (ret < 0) { error_setg(errp, "vhost-user-scsi: vhost initialization failed: %s", strerror(-ret)); - vhost_user_cleanup(user); - g_free(user); + vhost_user_cleanup(&s->vhost_user); return; } - s->vhost_user = user; - /* Channel and lun both are 0 for bootable vhost-user-scsi disk */ vsc->channel = 0; vsc->lun = 0; @@ -129,12 +122,7 @@ static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp) g_free(vsc->dev.vqs); virtio_scsi_common_unrealize(dev, errp); - - if (s->vhost_user) { - vhost_user_cleanup(s->vhost_user); - g_free(s->vhost_user); - s->vhost_user = NULL; - } + vhost_user_cleanup(&s->vhost_user); } static uint64_t vhost_user_scsi_get_features(VirtIODevice *vdev, diff --git a/hw/virtio/vhost-stub.c b/hw/virtio/vhost-stub.c index 049089b5e2..323dfcc46a 100644 --- a/hw/virtio/vhost-stub.c +++ b/hw/virtio/vhost-stub.c @@ -7,7 +7,7 @@ bool vhost_has_free_slot(void) return true; } -VhostUserState *vhost_user_init(void) +bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) { return NULL; } diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index b041343632..44795880d6 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1743,17 +1743,24 @@ static bool vhost_user_mem_section_filter(struct vhost_dev *dev, return result; } -VhostUserState *vhost_user_init(void) +bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) { - VhostUserState *user = g_new0(struct VhostUserState, 1); - - return user; + if (user->chr) { + error_setg(errp, "Cannot initialize vhost-user state"); + return false; + } + user->chr = chr; + return true; } void vhost_user_cleanup(VhostUserState *user) { int i; + if (!user->chr) { + return; + } + for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { if (user->notifier[i].addr) { object_unparent(OBJECT(&user->notifier[i].mr)); @@ -1761,6 +1768,7 @@ void vhost_user_cleanup(VhostUserState *user) user->notifier[i].addr = NULL; } } + user->chr = NULL; } const VhostOps user_ops = { diff --git a/net/vhost-user.c b/net/vhost-user.c index a39f9c9974..5e5b8f3fc9 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -291,14 +291,14 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, { Error *err = NULL; NetClientState *nc, *nc0 = NULL; - VhostUserState *user = NULL; NetVhostUserState *s = NULL; + VhostUserState *user; int i; assert(name); assert(queues > 0); - user = vhost_user_init(); + user = g_new0(struct VhostUserState, 1); if (!user) { error_report("failed to init vhost_user"); goto err; @@ -312,11 +312,11 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, if (!nc0) { nc0 = nc; s = DO_UPCAST(NetVhostUserState, nc, nc); - if (!qemu_chr_fe_init(&s->chr, chr, &err)) { + if (!qemu_chr_fe_init(&s->chr, chr, &err) || + !vhost_user_init(user, &s->chr, &err)) { error_report_err(err); goto err; } - user->chr = &s->chr; } s = DO_UPCAST(NetVhostUserState, nc, nc); s->vhost_user = user; From patchwork Mon Jun 18 16:17:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931027 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418brg6Qpkz9s1R for ; Tue, 19 Jun 2018 02:19:15 +1000 (AEST) Received: from localhost ([::1]:35733 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUws5-0002CQ-EF for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:19:13 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43828) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqm-0001rP-7N for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqh-0004yW-7a for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:52 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45460 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqh-0004yJ-2P for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:47 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B27E37DAC3 for ; Mon, 18 Jun 2018 16:17:46 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 60BDB2026D5B; Mon, 18 Jun 2018 16:17:46 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:08 +0200 Message-Id: <20180618161729.334-6-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:17:46 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:17:46 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 05/26] libvhost-user: exit by default on VHOST_USER_NONE X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Since commit 2566378d6d13bf4d28c7770bdbda5f7682594bbe, libvhost-user no longer panics on disconnect (rc == 0), and instead silently ignores an invalid VHOST_USER_NONE message. Without extra work from the API user, this will simply busy-loop on HUP events. The obvious thing to do is to exit(0) instead, while additional or different work can be done by overriding iface->process_msg(). Signed-off-by: Marc-André Lureau --- contrib/libvhost-user/libvhost-user.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index a6b46cdc03..41470daf57 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -1285,7 +1285,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg) case VHOST_USER_SET_CONFIG: return vu_set_config(dev, vmsg); case VHOST_USER_NONE: - break; + /* if you need processing before exit, override iface->process_msg */ + exit(0); case VHOST_USER_POSTCOPY_ADVISE: return vu_set_postcopy_advise(dev, vmsg); case VHOST_USER_POSTCOPY_LISTEN: From patchwork Mon Jun 18 16:17:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931038 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418bz157N5z9s1R for ; Tue, 19 Jun 2018 02:24:45 +1000 (AEST) Received: from localhost ([::1]:35760 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwxP-0006aq-9h for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:24:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43831) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqm-0001rX-8x for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqi-0004yv-Mu for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:52 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44976 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqi-0004yk-HW for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:48 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 323CF401EF03 for ; Mon, 18 Jun 2018 16:17:48 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id D5582200AC23; Mon, 18 Jun 2018 16:17:47 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:09 +0200 Message-Id: <20180618161729.334-7-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:17:48 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:17:48 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 06/26] vhost-user: wrap some read/write with retry handling X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Marc-André Lureau Reviewed-by: Philippe Mathieu-Daudé --- hw/virtio/vhost-user.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 44795880d6..5b4188bc27 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -975,7 +975,10 @@ static void slave_read(void *opaque) iov.iov_base = &hdr; iov.iov_len = VHOST_USER_HDR_SIZE; - size = recvmsg(u->slave_fd, &msgh, 0); + do { + size = recvmsg(u->slave_fd, &msgh, 0); + } while (size < 0 && (errno == EINTR || errno == EAGAIN)); + if (size != VHOST_USER_HDR_SIZE) { error_report("Failed to read from slave."); goto err; @@ -1004,7 +1007,10 @@ static void slave_read(void *opaque) } /* Read payload */ - size = read(u->slave_fd, &payload, hdr.size); + do { + size = read(u->slave_fd, &payload, hdr.size); + } while (size < 0 && (errno == EINTR || errno == EAGAIN)); + if (size != hdr.size) { error_report("Failed to read payload from slave."); goto err; @@ -1052,7 +1058,10 @@ static void slave_read(void *opaque) iovec[1].iov_base = &payload; iovec[1].iov_len = hdr.size; - size = writev(u->slave_fd, iovec, ARRAY_SIZE(iovec)); + do { + size = writev(u->slave_fd, iovec, ARRAY_SIZE(iovec)); + } while (size < 0 && (errno == EINTR || errno == EAGAIN)); + if (size != VHOST_USER_HDR_SIZE + hdr.size) { error_report("Failed to send msg reply to slave."); goto err; From patchwork Mon Jun 18 16:17:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931029 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418bvf0zzqz9s3R for ; Tue, 19 Jun 2018 02:21:50 +1000 (AEST) Received: from localhost ([::1]:35746 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwuZ-0004K1-Mb for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:21:47 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43829) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqm-0001rT-8A for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqk-0004zo-7M for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:52 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40948 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqk-0004zQ-1K for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:50 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AA23D81A4E99 for ; Mon, 18 Jun 2018 16:17:49 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4B2602026D5B; Mon, 18 Jun 2018 16:17:49 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:10 +0200 Message-Id: <20180618161729.334-8-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:17:49 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:17:49 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 07/26] qio: add qio_channel_command_new_spawn_with_pre_exec() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add a new function to let caller do some tuning thanks to a callback before exec(). Signed-off-by: Marc-André Lureau --- include/io/channel-command.h | 18 ++++++++++++++++++ io/channel-command.c | 33 ++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/include/io/channel-command.h b/include/io/channel-command.h index 336d47fa5c..96c833daab 100644 --- a/include/io/channel-command.h +++ b/include/io/channel-command.h @@ -71,6 +71,24 @@ qio_channel_command_new_pid(int writefd, int readfd, pid_t pid); +/** + * qio_channel_command_new_spawn_with_pre_exec: + * @argv: the NULL terminated list of command arguments + * @flags: the I/O mode, one of O_RDONLY, O_WRONLY, O_RDWR + * @errp: pointer to a NULL-initialized error object + * + * Create a channel for performing I/O with the + * command to be spawned with arguments @argv. + * + * Returns: the command channel object, or NULL on error + */ +QIOChannelCommand * +qio_channel_command_new_spawn_with_pre_exec(const char *const argv[], + int flags, + void (*pre_exec_cb)(void *), + void *data, + Error **errp); + /** * qio_channel_command_new_spawn: * @argv: the NULL terminated list of command arguments diff --git a/io/channel-command.c b/io/channel-command.c index 3e7eb17eff..05903ff194 100644 --- a/io/channel-command.c +++ b/io/channel-command.c @@ -46,9 +46,12 @@ qio_channel_command_new_pid(int writefd, #ifndef WIN32 QIOChannelCommand * -qio_channel_command_new_spawn(const char *const argv[], - int flags, - Error **errp) +qio_channel_command_new_spawn_with_pre_exec(const char *const argv[], + int flags, + void (*pre_exec_cb)(void *), + void *data, + Error **errp) + { pid_t pid = -1; int stdinfd[2] = { -1, -1 }; @@ -104,6 +107,10 @@ qio_channel_command_new_spawn(const char *const argv[], close(devnull); } + if (pre_exec_cb) { + pre_exec_cb(data); + } + execv(argv[0], (char * const *)argv); _exit(1); } @@ -139,12 +146,13 @@ qio_channel_command_new_spawn(const char *const argv[], } return NULL; } - #else /* WIN32 */ QIOChannelCommand * -qio_channel_command_new_spawn(const char *const argv[], - int flags, - Error **errp) +qio_channel_command_new_spawn_with_pre_exec(const char *const argv[], + int flags, + void (*pre_exec_cb)(void *), + void *data, + Error **errp) { error_setg_errno(errp, ENOSYS, "Command spawn not supported on this platform"); @@ -152,6 +160,17 @@ qio_channel_command_new_spawn(const char *const argv[], } #endif /* WIN32 */ + +QIOChannelCommand * +qio_channel_command_new_spawn(const char *const argv[], + int flags, + Error **errp) +{ + return qio_channel_command_new_spawn_with_pre_exec(argv, flags, + NULL, NULL, errp); +} + + #ifndef WIN32 static int qio_channel_command_abort(QIOChannelCommand *ioc, Error **errp) From patchwork Mon Jun 18 16:17:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931031 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418bvz0SL2z9s3M for ; Tue, 19 Jun 2018 02:22:07 +1000 (AEST) Received: from localhost ([::1]:35750 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwuq-0004Ws-MF for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:22:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43858) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqn-0001t2-O1 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwql-00050y-Qe for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:53 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40952 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwql-00050d-KF for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:51 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4032B80125CE for ; Mon, 18 Jun 2018 16:17:51 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id CDC43200AC23; Mon, 18 Jun 2018 16:17:50 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:11 +0200 Message-Id: <20180618161729.334-9-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:17:51 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:17:51 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 08/26] Add vhost-user-backend X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Create a vhost-user-backend object that holds a connection to a vhost-user backend and can be referenced from virtio devices that support it. See later patches for input & gpu usage. A chardev can be specified to communicate with the vhost-user backend, ex: -chardev socket,id=char0,path=/tmp/foo.sock -object vhost-user-backend,id=vuid,chardev=char0. Signed-off-by: Marc-André Lureau --- include/sysemu/vhost-user-backend.h | 60 +++++++ backends/vhost-user.c | 257 ++++++++++++++++++++++++++++ vl.c | 3 +- backends/Makefile.objs | 3 +- 4 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 include/sysemu/vhost-user-backend.h create mode 100644 backends/vhost-user.c diff --git a/include/sysemu/vhost-user-backend.h b/include/sysemu/vhost-user-backend.h new file mode 100644 index 0000000000..60f811cae7 --- /dev/null +++ b/include/sysemu/vhost-user-backend.h @@ -0,0 +1,60 @@ +/* + * QEMU vhost-user backend + * + * Copyright (C) 2018 Red Hat Inc + * + * Authors: + * Marc-André Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_VHOST_USER_BACKEND_H +#define QEMU_VHOST_USER_BACKEND_H + +#include "qom/object.h" +#include "exec/memory.h" +#include "qemu/option.h" +#include "qemu/bitmap.h" +#include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-user.h" +#include "chardev/char-fe.h" +#include "io/channel.h" + +#define TYPE_VHOST_USER_BACKEND "vhost-user-backend" +#define VHOST_USER_BACKEND(obj) \ + OBJECT_CHECK(VhostUserBackend, (obj), TYPE_VHOST_USER_BACKEND) +#define VHOST_USER_BACKEND_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VhostUserBackendClass, (obj), TYPE_VHOST_USER_BACKEND) +#define VHOST_USER_BACKEND_CLASS(klass) \ + OBJECT_CLASS_CHECK(VhostUserBackendClass, (klass), TYPE_VHOST_USER_BACKEND) + +typedef struct VhostUserBackend VhostUserBackend; +typedef struct VhostUserBackendClass VhostUserBackendClass; + +struct VhostUserBackendClass { + ObjectClass parent_class; +}; + +struct VhostUserBackend { + /* private */ + Object parent; + + char *cmd; + char *chr_name; + + CharBackend chr; + VhostUserState vhost_user; + struct vhost_dev dev; + QIOChannel *child; + VirtIODevice *vdev; + bool started; + bool completed; +}; + +int vhost_user_backend_dev_init(VhostUserBackend *b, VirtIODevice *vdev, + unsigned nvqs, Error **errp); +void vhost_user_backend_start(VhostUserBackend *b); +void vhost_user_backend_stop(VhostUserBackend *b); + +#endif diff --git a/backends/vhost-user.c b/backends/vhost-user.c new file mode 100644 index 0000000000..db97037306 --- /dev/null +++ b/backends/vhost-user.c @@ -0,0 +1,257 @@ +/* + * QEMU vhost-user backend + * + * Copyright (C) 2018 Red Hat Inc + * + * Authors: + * Marc-André Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + + +#include "qemu/osdep.h" +#include "hw/qdev.h" +#include "qapi/error.h" +#include "qapi/qmp/qerror.h" +#include "qemu/error-report.h" +#include "qom/object_interfaces.h" +#include "sysemu/vhost-user-backend.h" +#include "sysemu/kvm.h" +#include "io/channel-command.h" +#include "hw/virtio/virtio-bus.h" + +static bool +ioeventfd_enabled(void) +{ + return kvm_enabled() && kvm_eventfds_enabled(); +} + +int +vhost_user_backend_dev_init(VhostUserBackend *b, VirtIODevice *vdev, + unsigned nvqs, Error **errp) +{ + int ret; + + assert(!b->vdev && vdev); + + if (!ioeventfd_enabled()) { + error_setg(errp, "vhost initialization failed: requires kvm"); + return -1; + } + + if (!vhost_user_init(&b->vhost_user, &b->chr, errp)) { + return -1; + } + + b->vdev = vdev; + b->dev.nvqs = nvqs; + b->dev.vqs = g_new(struct vhost_virtqueue, nvqs); + + ret = vhost_dev_init(&b->dev, &b->vhost_user, VHOST_BACKEND_TYPE_USER, 0); + if (ret < 0) { + error_setg_errno(errp, -ret, "vhost initialization failed"); + return -1; + } + + return 0; +} + +void +vhost_user_backend_start(VhostUserBackend *b) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret, i ; + + if (b->started) { + return; + } + + if (!k->set_guest_notifiers) { + error_report("binding does not support guest notifiers"); + return; + } + + ret = vhost_dev_enable_notifiers(&b->dev, b->vdev); + if (ret < 0) { + return; + } + + ret = k->set_guest_notifiers(qbus->parent, b->dev.nvqs, true); + if (ret < 0) { + error_report("Error binding guest notifier"); + goto err_host_notifiers; + } + + b->dev.acked_features = b->vdev->guest_features; + ret = vhost_dev_start(&b->dev, b->vdev); + if (ret < 0) { + error_report("Error start vhost dev"); + goto err_guest_notifiers; + } + + /* guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < b->dev.nvqs; i++) { + vhost_virtqueue_mask(&b->dev, b->vdev, + b->dev.vq_index + i, false); + } + + b->started = true; + return; + +err_guest_notifiers: + k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false); +err_host_notifiers: + vhost_dev_disable_notifiers(&b->dev, b->vdev); +} + +void +vhost_user_backend_stop(VhostUserBackend *b) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + int ret = 0; + + if (!b->started) { + return; + } + + vhost_dev_stop(&b->dev, b->vdev); + + if (k->set_guest_notifiers) { + ret = k->set_guest_notifiers(qbus->parent, + b->dev.nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + } + } + assert(ret >= 0); + + vhost_dev_disable_notifiers(&b->dev, b->vdev); + b->started = false; +} + +static void +pre_exec_cb(void *data) +{ + int *sv = data; + int maxfd = sysconf(_SC_OPEN_MAX); + int fd; + + dup2(sv[1], 3); + for (fd = 4; fd < maxfd; fd++) { + close(fd); + } +} + +static void +vhost_user_backend_complete(UserCreatable *uc, Error **errp) +{ + VhostUserBackend *b = VHOST_USER_BACKEND(uc); + Chardev *chr; + + if (!b->chr_name) { + error_setg(errp, "You must specificy 'chardev'."); + return; + } + + chr = qemu_chr_find(b->chr_name); + if (chr == NULL) { + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Chardev '%s' not found", b->chr_name); + return; + } + + if (!qemu_chr_fe_init(&b->chr, chr, errp)) { + return; + } + + b->completed = true; + /* could vhost_dev_init() happen here, so early vhost-user message + * can be exchanged */ +} + +static void set_chardev(Object *obj, const char *value, Error **errp) +{ + VhostUserBackend *b = VHOST_USER_BACKEND(obj); + + if (b->completed) { + error_setg(errp, QERR_PERMISSION_DENIED); + } else { + g_free(b->chr_name); + b->chr_name = g_strdup(value); + } +} + +static char *get_chardev(Object *obj, Error **errp) +{ + VhostUserBackend *b = VHOST_USER_BACKEND(obj); + Chardev *chr = qemu_chr_fe_get_driver(&b->chr); + + if (chr && chr->label) { + return g_strdup(chr->label); + } + + return NULL; +} + +static void vhost_user_backend_init(Object *obj) +{ + object_property_add_str(obj, "chardev", get_chardev, set_chardev, NULL); +} + +static void vhost_user_backend_finalize(Object *obj) +{ + VhostUserBackend *b = VHOST_USER_BACKEND(obj); + + g_free(b->dev.vqs); + g_free(b->chr_name); + + vhost_user_cleanup(&b->vhost_user); + qemu_chr_fe_deinit(&b->chr, true); + + if (b->child) { + object_unref(OBJECT(b->child)); + } +} + +static bool +vhost_user_backend_can_be_deleted(UserCreatable *uc) +{ + return true; +} + +static void +vhost_user_backend_class_init(ObjectClass *oc, void *data) +{ + UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); + + ucc->complete = vhost_user_backend_complete; + ucc->can_be_deleted = vhost_user_backend_can_be_deleted; +} + +static const TypeInfo vhost_user_backend_info = { + .name = TYPE_VHOST_USER_BACKEND, + .parent = TYPE_OBJECT, + .instance_size = sizeof(VhostUserBackend), + .instance_init = vhost_user_backend_init, + .instance_finalize = vhost_user_backend_finalize, + .class_size = sizeof(VhostUserBackendClass), + .class_init = vhost_user_backend_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void register_types(void) +{ + type_register_static(&vhost_user_backend_info); +} + +type_init(register_types); diff --git a/vl.c b/vl.c index 6e34fb348d..1c21339ba7 100644 --- a/vl.c +++ b/vl.c @@ -2718,7 +2718,8 @@ static bool object_create_initial(const char *type) } #if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX) - if (g_str_equal(type, "cryptodev-vhost-user")) { + if (g_str_equal(type, "cryptodev-vhost-user") || + g_str_equal(type, "vhost-user-backend")) { return false; } #endif diff --git a/backends/Makefile.objs b/backends/Makefile.objs index ad7c0325ed..1ffcf76bb1 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -12,7 +12,8 @@ common-obj-y += cryptodev-builtin.o ifeq ($(CONFIG_VIRTIO),y) common-obj-y += cryptodev-vhost.o common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) += \ - cryptodev-vhost-user.o + cryptodev-vhost-user.o \ + vhost-user.o endif common-obj-$(CONFIG_LINUX) += hostmem-memfd.o From patchwork Mon Jun 18 16:17:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931026 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418brC1DBxz9s1R for ; Tue, 19 Jun 2018 02:18:51 +1000 (AEST) Received: from localhost ([::1]:35730 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrg-0001vj-Lz for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:18:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43874) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqo-0001tv-Md for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqn-00051z-Dx for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:54 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57716 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqn-00051Z-7v for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:53 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BBCD4402178A for ; Mon, 18 Jun 2018 16:17:52 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5D667111DCEA; Mon, 18 Jun 2018 16:17:52 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:12 +0200 Message-Id: <20180618161729.334-10-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 18 Jun 2018 16:17:52 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 18 Jun 2018 16:17:52 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 09/26] HACK: vhost-user-backend: allow to specify binary to execute X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" An executable with its arguments may be given as 'cmd' property, ex: -object vhost-user-backend,id=vui,cmd="./vhost-user-input /dev/input..". The executable is then spawn and, by convention, the vhost-user socket is passed as fd=3. It may be considered a security breach to allow creating processes that may execute arbitrary executables, so this may be restricted to some known executables (via signature etc) or directory. To make the patch more acceptable, the command argument would have to be passed via an array (probably via -object json: syntax), instead of using g_shell_parse_argv(). Signed-off-by: Marc-André Lureau --- backends/vhost-user.c | 83 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/backends/vhost-user.c b/backends/vhost-user.c index db97037306..32d3ec0e8b 100644 --- a/backends/vhost-user.c +++ b/backends/vhost-user.c @@ -154,26 +154,87 @@ vhost_user_backend_complete(UserCreatable *uc, Error **errp) { VhostUserBackend *b = VHOST_USER_BACKEND(uc); Chardev *chr; + char **argv = NULL; - if (!b->chr_name) { - error_setg(errp, "You must specificy 'chardev'."); + if (!!b->chr_name + !!b->cmd != 1) { + error_setg(errp, "You may specificy only one of 'chardev' or 'cmd'."); return; } - chr = qemu_chr_find(b->chr_name); - if (chr == NULL) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Chardev '%s' not found", b->chr_name); - return; - } + if (b->chr_name) { + chr = qemu_chr_find(b->chr_name); + if (chr == NULL) { + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Chardev '%s' not found", b->chr_name); + return; + } - if (!qemu_chr_fe_init(&b->chr, chr, errp)) { - return; + if (!qemu_chr_fe_init(&b->chr, chr, errp)) { + return; + } + } else { + QIOChannelCommand *child; + GError *err; + int sv[2]; + + if (!g_shell_parse_argv(b->cmd, NULL, &argv, &err)) { + error_setg(errp, "Fail to parse command: %s", err->message); + g_error_free(err); + return; + } + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { + error_setg_errno(errp, errno, "socketpair() failed"); + goto end; + } + + chr = CHARDEV(object_new(TYPE_CHARDEV_SOCKET)); + if (!chr || qemu_chr_add_client(chr, sv[0]) == -1) { + error_setg(errp, "Failed to make socket chardev"); + object_unref(OBJECT(chr)); + goto end; + } + + if (!qemu_chr_fe_init(&b->chr, chr, errp)) { + goto end; + } + + child = qio_channel_command_new_spawn_with_pre_exec( + (const char * const *)argv, O_RDONLY | O_WRONLY, + pre_exec_cb, sv, errp); + if (!child) { + goto end; + } + b->child = QIO_CHANNEL(child); + + close(sv[1]); } b->completed = true; /* could vhost_dev_init() happen here, so early vhost-user message * can be exchanged */ +end: + g_strfreev(argv); +} + +static char *get_cmd(Object *obj, Error **errp) +{ + VhostUserBackend *b = VHOST_USER_BACKEND(obj); + + return g_strdup(b->cmd); +} + +static void set_cmd(Object *obj, const char *str, Error **errp) +{ + VhostUserBackend *b = VHOST_USER_BACKEND(obj); + + if (b->child) { + error_setg(errp, "cannot change property value"); + return; + } + + g_free(b->cmd); + b->cmd = g_strdup(str); } static void set_chardev(Object *obj, const char *value, Error **errp) @@ -202,6 +263,7 @@ static char *get_chardev(Object *obj, Error **errp) static void vhost_user_backend_init(Object *obj) { + object_property_add_str(obj, "cmd", get_cmd, set_cmd, NULL); object_property_add_str(obj, "chardev", get_chardev, set_chardev, NULL); } @@ -210,6 +272,7 @@ static void vhost_user_backend_finalize(Object *obj) VhostUserBackend *b = VHOST_USER_BACKEND(obj); g_free(b->dev.vqs); + g_free(b->cmd); g_free(b->chr_name); vhost_user_cleanup(&b->vhost_user); From patchwork Mon Jun 18 16:17:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931040 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418bzR6F57z9s1R for ; Tue, 19 Jun 2018 02:25:07 +1000 (AEST) Received: from localhost ([::1]:35763 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwxl-0006r1-Cq for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:25:05 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43892) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqp-0001un-OS for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqo-00053Y-QJ for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:55 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44978 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqo-00052x-LA for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:17:54 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2ABDB401EF03 for ; Mon, 18 Jun 2018 16:17:54 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id D34762026D5B; Mon, 18 Jun 2018 16:17:53 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:13 +0200 Message-Id: <20180618161729.334-11-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:17:54 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:17:54 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 10/26] vhost-user: split vhost_user_read() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Split vhost_user_read(), so only header can be read with vhost_user_read_header(). Signed-off-by: Marc-André Lureau --- hw/virtio/vhost-user.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 5b4188bc27..29f8568a13 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -210,7 +210,7 @@ static bool ioeventfd_enabled(void) return kvm_enabled() && kvm_eventfds_enabled(); } -static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) +static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) { struct vhost_user *u = dev->opaque; CharBackend *chr = u->user->chr; @@ -221,7 +221,7 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) if (r != size) { error_report("Failed to read msg header. Read %d instead of %d." " Original request %d.", r, size, msg->hdr.request); - goto fail; + return -1; } /* validate received flags */ @@ -229,7 +229,21 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) error_report("Failed to read msg header." " Flags 0x%x instead of 0x%x.", msg->hdr.flags, VHOST_USER_REPLY_MASK | VHOST_USER_VERSION); - goto fail; + return -1; + } + + return 0; +} + +static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) +{ + struct vhost_user *u = dev->opaque; + CharBackend *chr = u->user->chr; + uint8_t *p = (uint8_t *) msg; + int r, size; + + if (vhost_user_read_header(dev, msg) < 0) { + return -1; } /* validate message size is sane */ @@ -237,7 +251,7 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) error_report("Failed to read msg header." " Size %d exceeds the maximum %zu.", msg->hdr.size, VHOST_USER_PAYLOAD_SIZE); - goto fail; + return -1; } if (msg->hdr.size) { @@ -247,14 +261,11 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) if (r != size) { error_report("Failed to read msg payload." " Read %d instead of %d.", r, msg->hdr.size); - goto fail; + return -1; } } return 0; - -fail: - return -1; } static int process_message_reply(struct vhost_dev *dev, From patchwork Mon Jun 18 16:17:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931042 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418c2N2T0kz9s1R for ; Tue, 19 Jun 2018 02:27:40 +1000 (AEST) Received: from localhost ([::1]:35778 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx0E-0000cJ-0X for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:27:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43973) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqx-00022R-Sr for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqu-00056F-IJ for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:03 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:60976 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqu-000569-DX for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:00 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 14F6A401DE60 for ; Mon, 18 Jun 2018 16:18:00 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 617CF7C4B; Mon, 18 Jun 2018 16:17:55 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:14 +0200 Message-Id: <20180618161729.334-12-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 18 Jun 2018 16:18:00 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 18 Jun 2018 16:18:00 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 11/26] vhost-user: add vhost_user_input_get_config() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Ask vhost user input backend the list of virtio_input_config. Signed-off-by: Marc-André Lureau --- include/hw/virtio/vhost-backend.h | 4 +++ hw/virtio/vhost-user.c | 59 +++++++++++++++++++++++++++++++ docs/interop/vhost-user.txt | 7 ++++ 3 files changed, 70 insertions(+) diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 81283ec50f..1fca321d8a 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -12,6 +12,7 @@ #define VHOST_BACKEND_H #include "exec/memory.h" +#include "standard-headers/linux/virtio_input.h" typedef enum VhostBackendType { VHOST_BACKEND_TYPE_NONE = 0, @@ -160,4 +161,7 @@ int vhost_backend_invalidate_device_iotlb(struct vhost_dev *dev, int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev, struct vhost_iotlb_msg *imsg); +int vhost_user_input_get_config(struct vhost_dev *dev, + struct virtio_input_config **config); + #endif /* VHOST_BACKEND_H */ diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 29f8568a13..cbd2900f39 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -89,6 +89,7 @@ typedef enum VhostUserRequest { VHOST_USER_POSTCOPY_ADVISE = 28, VHOST_USER_POSTCOPY_LISTEN = 29, VHOST_USER_POSTCOPY_END = 30, + VHOST_USER_INPUT_GET_CONFIG, VHOST_USER_MAX } VhostUserRequest; @@ -338,6 +339,64 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, return 0; } +static void *vhost_user_read_size(struct vhost_dev *dev, uint32_t size) +{ + struct vhost_user *u = dev->opaque; + CharBackend *chr = u->user->chr; + int r; + uint8_t *p = g_malloc(size); + + r = qemu_chr_fe_read_all(chr, p, size); + if (r != size) { + error_report("Failed to read msg payload." + " Read %d instead of %d.", r, size); + return NULL; + } + + return p; +} + +int vhost_user_input_get_config(struct vhost_dev *dev, + struct virtio_input_config **config) +{ + void *p = NULL; + VhostUserMsg msg = { + .hdr.request = VHOST_USER_INPUT_GET_CONFIG, + .hdr.flags = VHOST_USER_VERSION, + }; + + if (vhost_user_write(dev, &msg, NULL, 0) < 0) { + goto err; + } + + if (vhost_user_read_header(dev, &msg) < 0) { + goto err; + } + + p = vhost_user_read_size(dev, msg.hdr.size); + if (!p) { + goto err; + } + + if (msg.hdr.request != VHOST_USER_INPUT_GET_CONFIG) { + error_report("Received unexpected msg type. Expected %d received %d", + VHOST_USER_INPUT_GET_CONFIG, msg.hdr.request); + goto err; + } + + if (msg.hdr.size % sizeof(struct virtio_input_config)) { + error_report("Invalid msg size"); + goto err; + } + + *config = p; + return msg.hdr.size / sizeof(struct virtio_input_config); + +err: + g_free(p); + return -1; +} + static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, struct vhost_log *log) { diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt index d51fd58242..2efa44d124 100644 --- a/docs/interop/vhost-user.txt +++ b/docs/interop/vhost-user.txt @@ -761,6 +761,13 @@ Master message types was previously sent. The value returned is an error indication; 0 is success. + * VHOST_USER_INPUT_GET_CONFIG + Id: TBD + Master payload: N/A + Slave payload: (struct virtio_input_config)* + + Ask vhost user input backend the list of virtio_input_config. + Slave message types ------------------- From patchwork Mon Jun 18 16:17:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931046 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418c5b06rbz9s1R for ; Tue, 19 Jun 2018 02:30:27 +1000 (AEST) Received: from localhost ([::1]:35792 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx2u-0002vF-KV for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:30:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43974) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwqx-00022S-TB for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqw-00056b-5M for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:03 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:60980 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqv-00056U-Vr for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:02 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9FA68401DE68 for ; Mon, 18 Jun 2018 16:18:01 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 53A002026D5B; Mon, 18 Jun 2018 16:18:01 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:15 +0200 Message-Id: <20180618161729.334-13-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 18 Jun 2018 16:18:01 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 18 Jun 2018 16:18:01 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 12/26] libvhost-user: export vug_source_new() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Simplify the creation of FD sources for other users. Signed-off-by: Marc-André Lureau --- contrib/libvhost-user/libvhost-user-glib.h | 3 +++ contrib/libvhost-user/libvhost-user-glib.c | 15 +++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/contrib/libvhost-user/libvhost-user-glib.h b/contrib/libvhost-user/libvhost-user-glib.h index 6b2110b94c..d3200f3afc 100644 --- a/contrib/libvhost-user/libvhost-user-glib.h +++ b/contrib/libvhost-user/libvhost-user-glib.h @@ -29,4 +29,7 @@ void vug_init(VugDev *dev, int socket, vu_panic_cb panic, const VuDevIface *iface); void vug_deinit(VugDev *dev); +GSource *vug_source_new(VugDev *dev, int fd, GIOCondition cond, + vu_watch_cb vu_cb, gpointer data); + #endif /* LIBVHOST_USER_GLIB_H */ diff --git a/contrib/libvhost-user/libvhost-user-glib.c b/contrib/libvhost-user/libvhost-user-glib.c index 545f089587..0e2c467f28 100644 --- a/contrib/libvhost-user/libvhost-user-glib.c +++ b/contrib/libvhost-user/libvhost-user-glib.c @@ -69,8 +69,8 @@ static GSourceFuncs vug_src_funcs = { }; static GSource * -vug_source_new(VuDev *dev, int fd, GIOCondition cond, - vu_watch_cb vu_cb, gpointer data) +_vug_source_new(VuDev *dev, int fd, GIOCondition cond, + vu_watch_cb vu_cb, gpointer data) { GSource *gsrc; VugSrc *src; @@ -95,6 +95,13 @@ vug_source_new(VuDev *dev, int fd, GIOCondition cond, return gsrc; } +GSource * +vug_source_new(VugDev *dev, int fd, GIOCondition cond, + vu_watch_cb vu_cb, gpointer data) +{ + return _vug_source_new(&dev->parent, fd, cond, vu_cb, data); +} + static void set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb, void *pvt) { @@ -106,7 +113,7 @@ set_watch(VuDev *vu_dev, int fd, int vu_evt, vu_watch_cb cb, void *pvt) g_assert(cb); dev = container_of(vu_dev, VugDev, parent); - src = vug_source_new(vu_dev, fd, vu_evt, cb, pvt); + src = _vug_source_new(vu_dev, fd, vu_evt, cb, pvt); g_hash_table_replace(dev->fdmap, GINT_TO_POINTER(fd), src); } @@ -141,7 +148,7 @@ vug_init(VugDev *dev, int socket, dev->fdmap = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify) g_source_destroy); - dev->src = vug_source_new(&dev->parent, socket, G_IO_IN, vug_watch, NULL); + dev->src = _vug_source_new(&dev->parent, socket, G_IO_IN, vug_watch, NULL); } void From patchwork Mon Jun 18 16:17:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931044 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418c2t5wB1z9s1R for ; Tue, 19 Jun 2018 02:28:06 +1000 (AEST) Received: from localhost ([::1]:35784 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx0e-0000wF-Ad for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:28:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44013) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwr2-00025I-Mv for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqx-000573-S2 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:08 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45470 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqx-00056y-Mz for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:03 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5CA297DAC3 for ; Mon, 18 Jun 2018 16:18:03 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id C9AF8200AC23; Mon, 18 Jun 2018 16:18:02 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:16 +0200 Message-Id: <20180618161729.334-14-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:03 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:03 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 13/26] contrib: add vhost-user-input X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add a vhost-user input backend example, based on virtio-input-host device. It takes an evdev path as argument, and can be associated with a vhost-user-backend object, ex: -object vhost-user-backend,id=vuid,cmd="vhost-user-input /dev/input/event0" Signed-off-by: Marc-André Lureau --- contrib/libvhost-user/libvhost-user.h | 1 + contrib/vhost-user-input/main.c | 364 +++++++++++++++++++++++++ Makefile | 3 + Makefile.objs | 1 + configure | 3 + contrib/vhost-user-input/Makefile.objs | 1 + 6 files changed, 373 insertions(+) create mode 100644 contrib/vhost-user-input/main.c create mode 100644 contrib/vhost-user-input/Makefile.objs diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h index 4aa55b4d2d..40d7cbfc2a 100644 --- a/contrib/libvhost-user/libvhost-user.h +++ b/contrib/libvhost-user/libvhost-user.h @@ -91,6 +91,7 @@ typedef enum VhostUserRequest { VHOST_USER_POSTCOPY_ADVISE = 28, VHOST_USER_POSTCOPY_LISTEN = 29, VHOST_USER_POSTCOPY_END = 30, + VHOST_USER_INPUT_GET_CONFIG, VHOST_USER_MAX } VhostUserRequest; diff --git a/contrib/vhost-user-input/main.c b/contrib/vhost-user-input/main.c new file mode 100644 index 0000000000..fe12d1ce1f --- /dev/null +++ b/contrib/vhost-user-input/main.c @@ -0,0 +1,364 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include +#include + +#include "qemu/osdep.h" +#include "qemu/iov.h" +#include "qemu/bswap.h" +#include "contrib/libvhost-user/libvhost-user.h" +#include "contrib/libvhost-user/libvhost-user-glib.h" +#include "standard-headers/linux/virtio_input.h" + +typedef struct virtio_input_event virtio_input_event; +typedef struct virtio_input_config virtio_input_config; + +typedef struct VuInput { + VugDev dev; + GSource *evsrc; + int evdevfd; + GArray *config; + virtio_input_event *queue; + uint32_t qindex, qsize; +} VuInput; + +static void vi_input_send(VuInput *vi, struct virtio_input_event *event) +{ + VuDev *dev = &vi->dev.parent; + VuVirtq *vq = vu_get_queue(dev, 0); + VuVirtqElement *elem; + unsigned have, need; + int i, len; + + /* queue up events ... */ + if (vi->qindex == vi->qsize) { + vi->qsize++; + vi->queue = realloc(vi->queue, vi->qsize * + sizeof(virtio_input_event)); + } + vi->queue[vi->qindex++] = *event; + + /* ... until we see a report sync ... */ + if (event->type != htole16(EV_SYN) || + event->code != htole16(SYN_REPORT)) { + return; + } + + /* ... then check available space ... */ + need = sizeof(virtio_input_event) * vi->qindex; + vu_queue_get_avail_bytes(dev, vq, &have, NULL, need, 0); + if (have < need) { + vi->qindex = 0; + g_warning("ENOSPC in vq, dropping events"); + return; + } + + /* ... and finally pass them to the guest */ + for (i = 0; i < vi->qindex; i++) { + elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); + if (!elem) { + /* should not happen, we've checked for space beforehand */ + g_warning("%s: Huh? No vq elem available ...\n", __func__); + return; + } + len = iov_from_buf(elem->in_sg, elem->in_num, + 0, vi->queue + i, sizeof(virtio_input_event)); + vu_queue_push(dev, vq, elem, len); + g_free(elem); + } + vu_queue_notify(&vi->dev.parent, vq); + vi->qindex = 0; +} + +static void +vi_evdev_watch(VuDev *dev, int condition, void *data) +{ + VuInput *vi = data; + int fd = vi->evdevfd; + + g_debug("Got evdev condition %x", condition); + + struct virtio_input_event virtio; + struct input_event evdev; + int rc; + + for (;;) { + rc = read(fd, &evdev, sizeof(evdev)); + if (rc != sizeof(evdev)) { + break; + } + + g_debug("input %d %d %d", evdev.type, evdev.code, evdev.value); + + virtio.type = htole16(evdev.type); + virtio.code = htole16(evdev.code); + virtio.value = htole32(evdev.value); + vi_input_send(vi, &virtio); + } +} + + +static void vi_handle_status(VuInput *vi, virtio_input_event *event) +{ + struct input_event evdev; + int rc; + + if (gettimeofday(&evdev.time, NULL)) { + perror("vi_handle_status: gettimeofday"); + return; + } + + evdev.type = le16toh(event->type); + evdev.code = le16toh(event->code); + evdev.value = le32toh(event->value); + + rc = write(vi->evdevfd, &evdev, sizeof(evdev)); + if (rc == -1) { + perror("vi_host_handle_status: write"); + } +} + +static void vi_handle_sts(VuDev *dev, int qidx) +{ + VuInput *vi = container_of(dev, VuInput, dev.parent); + VuVirtq *vq = vu_get_queue(dev, qidx); + virtio_input_event event; + VuVirtqElement *elem; + int len; + + g_debug("%s", G_STRFUNC); + + for (;;) { + elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); + if (!elem) { + break; + } + + memset(&event, 0, sizeof(event)); + len = iov_to_buf(elem->out_sg, elem->out_num, + 0, &event, sizeof(event)); + vi_handle_status(vi, &event); + vu_queue_push(dev, vq, elem, len); + g_free(elem); + } + + vu_queue_notify(&vi->dev.parent, vq); +} + +static void +vi_panic(VuDev *dev, const char *msg) +{ + g_critical("%s\n", msg); + exit(1); +} + +static void +vi_queue_set_started(VuDev *dev, int qidx, bool started) +{ + VuInput *vi = container_of(dev, VuInput, dev.parent); + VuVirtq *vq = vu_get_queue(dev, qidx); + + g_debug("queue started %d:%d", qidx, started); + + if (qidx == 0) { + if (started && !vi->evsrc) { + vi->evsrc = vug_source_new(&vi->dev, vi->evdevfd, + G_IO_IN, vi_evdev_watch, vi); + } else if (!started) { + g_source_destroy(vi->evsrc); + vi->evsrc = NULL; + } + } else { + vu_set_queue_handler(dev, vq, started ? vi_handle_sts : NULL); + } +} + +static int +vi_process_msg(VuDev *dev, VhostUserMsg *vmsg, int *do_reply) +{ + VuInput *vi = container_of(dev, VuInput, dev.parent); + + switch (vmsg->request) { + case VHOST_USER_INPUT_GET_CONFIG: + vmsg->size = vi->config->len * sizeof(virtio_input_config); + vmsg->data = g_memdup(vi->config->data, vmsg->size); + *do_reply = true; + return 1; + default: + return 0; + } +} + +static const VuDevIface vuiface = { + .queue_set_started = vi_queue_set_started, + .process_msg = vi_process_msg, +}; + +static void +vi_bits_config(VuInput *vi, int type, int count) +{ + virtio_input_config bits; + int rc, i, size = 0; + + memset(&bits, 0, sizeof(bits)); + rc = ioctl(vi->evdevfd, EVIOCGBIT(type, count / 8), bits.u.bitmap); + if (rc < 0) { + return; + } + + for (i = 0; i < count / 8; i++) { + if (bits.u.bitmap[i]) { + size = i + 1; + } + } + if (size == 0) { + return; + } + + bits.select = VIRTIO_INPUT_CFG_EV_BITS; + bits.subsel = type; + bits.size = size; + g_array_append_val(vi->config, bits); +} + +static int unix_sock_new(char *path) +{ + int sock; + struct sockaddr_un un; + size_t len; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock <= 0) { + perror("socket"); + return -1; + } + + un.sun_family = AF_UNIX; + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + len = sizeof(un.sun_family) + strlen(un.sun_path); + + unlink(path); + if (bind(sock, (struct sockaddr *)&un, len) < 0) { + perror("bind"); + goto fail; + } + + if (listen(sock, 1) < 0) { + perror("listen"); + goto fail; + } + + return sock; + +fail: + close(sock); + + return -1; +} + +static char **opt_fname; +static char *opt_socket_path; +static gboolean opt_nograb; + +static GOptionEntry entries[] = { + { "no-grab", 'n', 0, G_OPTION_ARG_NONE, &opt_nograb, + "Don't grab device", NULL }, + { "socket-path", 's', 0, G_OPTION_ARG_FILENAME, &opt_socket_path, + "Use UNIX socket path", "PATH" }, + { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_fname, + "EVDEV filename", "..." }, + { NULL, } +}; + +int +main(int argc, char *argv[]) +{ + GMainLoop *loop = NULL; + VuInput vi = { 0, }; + int rc, ver, fd; + virtio_input_config id; + struct input_id ids; + GError *error = NULL; + GOptionContext *context; + + context = g_option_context_new("EVDEV - vhost-user-input sample"); + g_option_context_add_main_entries(context, entries, NULL); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + g_printerr("Option parsing failed: %s\n", error->message); + exit(1); + } + if (!opt_fname || !opt_fname[0] || opt_fname[1]) { + g_printerr("Please specify a single EVDEV filename\n"); + exit(1); + } + + vi.evdevfd = open(opt_fname[0], O_RDWR); + if (vi.evdevfd < 0) { + g_printerr("Failed to open evdev: %s\n", g_strerror(errno)); + exit(1); + } + + rc = ioctl(vi.evdevfd, EVIOCGVERSION, &ver); + if (rc < 0) { + g_printerr("%s: is not an evdev device\n", argv[1]); + exit(1); + } + + if (!opt_nograb) { + rc = ioctl(vi.evdevfd, EVIOCGRAB, 1); + if (rc < 0) { + g_printerr("Failed to grab device\n"); + exit(1); + } + } + + vi.config = g_array_new(false, false, sizeof(virtio_input_config)); + memset(&id, 0, sizeof(id)); + ioctl(vi.evdevfd, EVIOCGNAME(sizeof(id.u.string) - 1), id.u.string); + id.select = VIRTIO_INPUT_CFG_ID_NAME; + id.size = strlen(id.u.string); + g_array_append_val(vi.config, id); + + if (ioctl(vi.evdevfd, EVIOCGID, &ids) == 0) { + memset(&id, 0, sizeof(id)); + id.select = VIRTIO_INPUT_CFG_ID_DEVIDS; + id.size = sizeof(struct virtio_input_devids); + id.u.ids.bustype = cpu_to_le16(ids.bustype); + id.u.ids.vendor = cpu_to_le16(ids.vendor); + id.u.ids.product = cpu_to_le16(ids.product); + id.u.ids.version = cpu_to_le16(ids.version); + g_array_append_val(vi.config, id); + } + + vi_bits_config(&vi, EV_KEY, KEY_CNT); + vi_bits_config(&vi, EV_REL, REL_CNT); + vi_bits_config(&vi, EV_ABS, ABS_CNT); + vi_bits_config(&vi, EV_MSC, MSC_CNT); + vi_bits_config(&vi, EV_SW, SW_CNT); + g_debug("config length: %u", vi.config->len); + + if (opt_socket_path) { + int lsock = unix_sock_new(opt_socket_path); + fd = accept(lsock, NULL, NULL); + close(lsock); + } else { + fd = 3; + } + if (fd == -1) { + g_printerr("Invalid socket"); + exit(1); + } + vug_init(&vi.dev, fd, vi_panic, &vuiface); + + loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(loop); + g_main_loop_unref(loop); + + vug_deinit(&vi.dev); + + return 0; +} diff --git a/Makefile b/Makefile index e46f2b625a..1d4d9441b1 100644 --- a/Makefile +++ b/Makefile @@ -421,6 +421,7 @@ dummy := $(call unnest-vars,, \ libvhost-user-obj-y \ vhost-user-scsi-obj-y \ vhost-user-blk-obj-y \ + vhost-user-input-obj-y \ qga-vss-dll-obj-y \ block-obj-y \ block-obj-m \ @@ -719,6 +720,8 @@ vhost-user-scsi$(EXESUF): $(vhost-user-scsi-obj-y) libvhost-user.a $(call LINK, $^) vhost-user-blk$(EXESUF): $(vhost-user-blk-obj-y) libvhost-user.a $(call LINK, $^) +vhost-user-input$(EXESUF): $(vhost-user-input-obj-y) libvhost-user.a libqemuutil.a + $(call LINK, $^) module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak $(call quiet-command,$(PYTHON) $< $@ \ diff --git a/Makefile.objs b/Makefile.objs index 7a9828da28..b0f48d667c 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -193,6 +193,7 @@ vhost-user-scsi.o-cflags := $(LIBISCSI_CFLAGS) vhost-user-scsi.o-libs := $(LIBISCSI_LIBS) vhost-user-scsi-obj-y = contrib/vhost-user-scsi/ vhost-user-blk-obj-y = contrib/vhost-user-blk/ +vhost-user-input-obj-y = contrib/vhost-user-input/ ###################################################################### trace-events-subdirs = diff --git a/configure b/configure index a8c4094c87..28aef55d06 100755 --- a/configure +++ b/configure @@ -5551,6 +5551,9 @@ if test "$want_tools" = "yes" ; then if [ "$ivshmem" = "yes" ]; then tools="ivshmem-client\$(EXESUF) ivshmem-server\$(EXESUF) $tools" fi + if [ "$linux" = "yes" ] ; then + tools="vhost-user-input\$(EXESUF) $tools" + fi fi if test "$softmmu" = yes ; then if test "$linux" = yes; then diff --git a/contrib/vhost-user-input/Makefile.objs b/contrib/vhost-user-input/Makefile.objs new file mode 100644 index 0000000000..b1fad90d51 --- /dev/null +++ b/contrib/vhost-user-input/Makefile.objs @@ -0,0 +1 @@ +vhost-user-input-obj-y = main.o From patchwork Mon Jun 18 16:17:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931034 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418bwL5gDtz9s1R for ; Tue, 19 Jun 2018 02:22:26 +1000 (AEST) Received: from localhost ([::1]:35752 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwvA-0004jt-9Q for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:22:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44004) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwr1-00023n-1K for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwqz-00058u-HN for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:07 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40958 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwqz-00058K-Au for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:05 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EEAB681A4E99 for ; Mon, 18 Jun 2018 16:18:04 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8A1957C5B; Mon, 18 Jun 2018 16:18:04 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:17 +0200 Message-Id: <20180618161729.334-15-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:18:04 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:18:04 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 14/26] Add vhost-user-input-pci X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add a new virtio-input device, which connects to a vhost-user backend. Usage: -object vhost-user-backend,id=vuid -device vhost-input-pci,vhost-user=vuid Signed-off-by: Marc-André Lureau --- hw/virtio/virtio-pci.h | 10 +++ include/hw/virtio/virtio-input.h | 14 ++++ hw/input/vhost-user-input.c | 110 +++++++++++++++++++++++++++++++ hw/virtio/virtio-pci.c | 20 ++++++ MAINTAINERS | 1 + hw/input/Makefile.objs | 1 + 6 files changed, 156 insertions(+) create mode 100644 hw/input/vhost-user-input.c diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 813082b0d7..c7e28e1b9c 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -54,6 +54,7 @@ typedef struct VirtIORngPCI VirtIORngPCI; typedef struct VirtIOInputPCI VirtIOInputPCI; typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; typedef struct VirtIOInputHostPCI VirtIOInputHostPCI; +typedef struct VHostUserInputPCI VHostUserInputPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VHostVSockPCI VHostVSockPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; @@ -376,6 +377,15 @@ struct VirtIOInputHostPCI { #endif +#define TYPE_VHOST_USER_INPUT_PCI "vhost-user-input-pci" +#define VHOST_USER_INPUT_PCI(obj) \ + OBJECT_CHECK(VHostUserInputPCI, (obj), TYPE_VHOST_USER_INPUT_PCI) + +struct VHostUserInputPCI { + VirtIOPCIProxy parent_obj; + VHostUserInput vhi; +}; + /* * virtio-gpu-pci: This extends VirtioPCIProxy. */ diff --git a/include/hw/virtio/virtio-input.h b/include/hw/virtio/virtio-input.h index 054c38836f..4fca03e796 100644 --- a/include/hw/virtio/virtio-input.h +++ b/include/hw/virtio/virtio-input.h @@ -2,6 +2,7 @@ #define QEMU_VIRTIO_INPUT_H #include "ui/input.h" +#include "sysemu/vhost-user-backend.h" /* ----------------------------------------------------------------- */ /* virtio input protocol */ @@ -42,11 +43,18 @@ typedef struct virtio_input_event virtio_input_event; #define VIRTIO_INPUT_HOST_GET_PARENT_CLASS(obj) \ OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT_HOST) +#define TYPE_VHOST_USER_INPUT "vhost-user-input" +#define VHOST_USER_INPUT(obj) \ + OBJECT_CHECK(VHostUserInput, (obj), TYPE_VHOST_USER_INPUT) +#define VHOST_USER_INPUT_GET_PARENT_CLASS(obj) \ + OBJECT_GET_PARENT_CLASS(obj, TYPE_VHOST_USER_INPUT) + typedef struct VirtIOInput VirtIOInput; typedef struct VirtIOInputClass VirtIOInputClass; typedef struct VirtIOInputConfig VirtIOInputConfig; typedef struct VirtIOInputHID VirtIOInputHID; typedef struct VirtIOInputHost VirtIOInputHost; +typedef struct VHostUserInput VHostUserInput; struct VirtIOInputConfig { virtio_input_config config; @@ -98,6 +106,12 @@ struct VirtIOInputHost { int fd; }; +struct VHostUserInput { + VirtIOInput parent_obj; + + VhostUserBackend *vhost; +}; + void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event); void virtio_input_init_config(VirtIOInput *vinput, virtio_input_config *config); diff --git a/hw/input/vhost-user-input.c b/hw/input/vhost-user-input.c new file mode 100644 index 0000000000..ef1b23a8b2 --- /dev/null +++ b/hw/input/vhost-user-input.c @@ -0,0 +1,110 @@ +/* + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" + +#include "hw/qdev.h" +#include "hw/virtio/virtio-input.h" + +static void vhost_input_realize(DeviceState *dev, Error **errp) +{ + VHostUserInput *vhi = VHOST_USER_INPUT(dev); + VirtIOInput *vinput = VIRTIO_INPUT(dev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + virtio_input_config *config; + int i, ret; + + if (!vhi->vhost) { + error_setg(errp, "'vhost-user' property is required"); + return; + } + + if (vhost_user_backend_dev_init(vhi->vhost, vdev, 2, errp) == -1) { + return; + } + + ret = vhost_user_input_get_config(&vhi->vhost->dev, &config); + if (ret < 0) { + error_setg(errp, "failed to get input config"); + return; + } + for (i = 0; i < ret; i++) { + virtio_input_add_config(vinput, &config[i]); + } + g_free(config); +} + +static void vhost_input_change_active(VirtIOInput *vinput) +{ + VHostUserInput *vhi = VHOST_USER_INPUT(vinput); + + if (vinput->active) { + vhost_user_backend_start(vhi->vhost); + } else { + vhost_user_backend_stop(vhi->vhost); + } +} + +static const VMStateDescription vmstate_vhost_input = { + .name = "vhost-user-input", + .unmigratable = 1, +}; + +static void vhost_input_class_init(ObjectClass *klass, void *data) +{ + VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_vhost_input; + vic->realize = vhost_input_realize; + vic->change_active = vhost_input_change_active; +} + +static void vhost_input_is_busy(const Object *obj, const char *name, + Object *val, Error **errp) +{ + VHostUserInput *vhi = VHOST_USER_INPUT(obj); + + if (vhi->vhost) { + error_setg(errp, "can't use already busy vhost-user"); + } else { + qdev_prop_allow_set_link_before_realize(obj, name, val, errp); + } +} + +static void vhost_input_init(Object *obj) +{ + VHostUserInput *vhi = VHOST_USER_INPUT(obj); + VirtIOInput *vinput = VIRTIO_INPUT(obj); + struct virtio_input_config vhost_input_config[] = { { /* empty list */ } }; + + virtio_input_init_config(vinput, vhost_input_config); + + object_property_add_link(obj, "vhost-user", TYPE_VHOST_USER_BACKEND, + (Object **)&vhi->vhost, + vhost_input_is_busy, + OBJ_PROP_LINK_STRONG, + &error_abort); +} + +static const TypeInfo vhost_input_info = { + .name = TYPE_VHOST_USER_INPUT, + .parent = TYPE_VIRTIO_INPUT, + .instance_size = sizeof(VHostUserInput), + .instance_init = vhost_input_init, + .class_init = vhost_input_class_init, +}; + +/* ----------------------------------------------------------------- */ + +static void vhost_input_register_types(void) +{ + type_register_static(&vhost_input_info); +} + +type_init(vhost_input_register_types) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 3a01fe90f0..6bb0575257 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2645,6 +2645,25 @@ static const TypeInfo virtio_host_pci_info = { }; #endif +static void vhost_input_pci_initfn(Object *obj) +{ + VHostUserInputPCI *dev = VHOST_USER_INPUT_PCI(obj); + + virtio_instance_init_common(obj, &dev->vhi, sizeof(dev->vhi), + TYPE_VHOST_USER_INPUT); + + object_property_add_alias(obj, "vhost-user", + OBJECT(&dev->vhi), "vhost-user", + &error_abort); +} + +static const TypeInfo vhost_input_pci_info = { + .name = TYPE_VHOST_USER_INPUT_PCI, + .parent = TYPE_VIRTIO_INPUT_PCI, + .instance_size = sizeof(VHostUserInputPCI), + .instance_init = vhost_input_pci_initfn, +}; + /* virtio-pci-bus */ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, @@ -2701,6 +2720,7 @@ static void virtio_pci_register_types(void) #ifdef CONFIG_LINUX type_register_static(&virtio_host_pci_info); #endif + type_register_static(&vhost_input_pci_info); type_register_static(&virtio_pci_bus_info); type_register_static(&virtio_pci_info); #ifdef CONFIG_VIRTFS diff --git a/MAINTAINERS b/MAINTAINERS index 0fb5f38f9f..773624f095 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1206,6 +1206,7 @@ L: qemu-s390x@nongnu.org virtio-input M: Gerd Hoffmann S: Maintained +F: hw/input/vhost-user-input.c F: hw/input/virtio-input*.c F: include/hw/virtio/virtio-input.h diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs index c8b00f71ec..6adc308cdd 100644 --- a/hw/input/Makefile.objs +++ b/hw/input/Makefile.objs @@ -11,6 +11,7 @@ common-obj-$(CONFIG_VIRTIO_INPUT) += virtio-input.o common-obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-hid.o ifeq ($(CONFIG_LINUX),y) common-obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-host.o +common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_VIRTIO_INPUT)) += vhost-user-input.o endif obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o From patchwork Mon Jun 18 16:17:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931050 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418c750B3Yz9s1R for ; Tue, 19 Jun 2018 02:31:45 +1000 (AEST) Received: from localhost ([::1]:35806 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx4A-0003xn-Ir for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:31:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44063) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrB-0002CR-RI for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwr5-0005An-EQ for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:17 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40964 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwr5-0005Ab-8X for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:11 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E179680125CE for ; Mon, 18 Jun 2018 16:18:10 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 19BFE111CA1D; Mon, 18 Jun 2018 16:18:05 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:18 +0200 Message-Id: <20180618161729.334-16-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:18:10 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 18 Jun 2018 16:18:10 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 15/26] vhost-user: add vhost_user_gpu_set_socket() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add a new vhost-user message to give a unix socket for gpu updates to a vhost-user backend. Back when I started that work, I added a new GPU channel because the vhost-user protocol wasn't bidirectional. Since then, there is a vhost-user-slave channel for the slave to send requests to the master. We could extend it with GPU messages. However, the GPU protocol is quite orthogonal to vhost-user and may not need the same kind of stability guarantees, thus I chose to have a new dedicated channel. Signed-off-by: Marc-André Lureau --- contrib/libvhost-user/libvhost-user.h | 1 + include/hw/virtio/vhost-backend.h | 1 + hw/virtio/vhost-user.c | 11 ++ MAINTAINERS | 6 + docs/interop/vhost-user-gpu.txt | 236 ++++++++++++++++++++++++++ docs/interop/vhost-user.txt | 8 + 6 files changed, 263 insertions(+) create mode 100644 docs/interop/vhost-user-gpu.txt diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h index 40d7cbfc2a..9899bfda9e 100644 --- a/contrib/libvhost-user/libvhost-user.h +++ b/contrib/libvhost-user/libvhost-user.h @@ -92,6 +92,7 @@ typedef enum VhostUserRequest { VHOST_USER_POSTCOPY_LISTEN = 29, VHOST_USER_POSTCOPY_END = 30, VHOST_USER_INPUT_GET_CONFIG, + VHOST_USER_GPU_SET_SOCKET, VHOST_USER_MAX } VhostUserRequest; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 1fca321d8a..daf9180c33 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -163,5 +163,6 @@ int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev, int vhost_user_input_get_config(struct vhost_dev *dev, struct virtio_input_config **config); +int vhost_user_gpu_set_socket(struct vhost_dev *dev, int fd); #endif /* VHOST_BACKEND_H */ diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index cbd2900f39..37864bc06a 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -90,6 +90,7 @@ typedef enum VhostUserRequest { VHOST_USER_POSTCOPY_LISTEN = 29, VHOST_USER_POSTCOPY_END = 30, VHOST_USER_INPUT_GET_CONFIG, + VHOST_USER_GPU_SET_SOCKET, VHOST_USER_MAX } VhostUserRequest; @@ -397,6 +398,16 @@ err: return -1; } +int vhost_user_gpu_set_socket(struct vhost_dev *dev, int fd) +{ + VhostUserMsg msg = { + .hdr.request = VHOST_USER_GPU_SET_SOCKET, + .hdr.flags = VHOST_USER_VERSION, + }; + + return vhost_user_write(dev, &msg, &fd, 1); +} + static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, struct vhost_log *log) { diff --git a/MAINTAINERS b/MAINTAINERS index 773624f095..e5dee15967 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1339,6 +1339,12 @@ F: hw/display/virtio-gpu* F: hw/display/virtio-vga.c F: include/hw/virtio/virtio-gpu.h +vhost-user-gpu +M: Marc-André Lureau +M: Gerd Hoffmann +S: Maintained +F: docs/interop/vhost-user-gpu.txt + Cirrus VGA M: Gerd Hoffmann S: Odd Fixes diff --git a/docs/interop/vhost-user-gpu.txt b/docs/interop/vhost-user-gpu.txt new file mode 100644 index 0000000000..309d07fd6d --- /dev/null +++ b/docs/interop/vhost-user-gpu.txt @@ -0,0 +1,236 @@ +======================= +Vhost-user-gpu Protocol +======================= + +This work is licensed under the terms of the GNU GPL, version 2 or later. +See the COPYING file in the top-level directory. + +Overview +======== + +The vhost-user-gpu protocol is aiming at sharing the rendering result +of a virtio-gpu, done from a vhost-user slave process to a vhost-user +master process (such as QEMU). It bears a resemblance to a display +server protocol, if you consider QEMU as the display server and the +slave as the client, but in a very limited way. Typically, it will +work by setting a scanout/display configuration, before sending flush +events for the display updates. It will also update the cursor shape +and position. + +The protocol is sent over a UNIX domain stream socket, since it uses +socket ancillary data to share opened file descriptors (DMABUF fds or +shared memory). + +Requests are sent by the slave, and the optional replies by the master. + +Wire format +=========== + +Unless specified differently, numbers are in the machine native byte +order. + +A vhost-user-gpu request consists of 2 header fields and a payload: + +:: + + ------------------------------------ + | u32:request | u32:size | payload | + ------------------------------------ + +- request: 32-bit type of the request +- size: 32-bit size of the payload + +A reply consists only of a payload, whose content depends on on the request. + + +Payload types +------------- + +VhostUserGpuCursorPos +^^^^^^^^^^^^^^^^^^^^^ + +:: + + ---------------------------------- + | u32:scanout-id | u32:x | u32:y | + ---------------------------------- + +- scanout-id: the scanout where the cursor is located +- x/y: the cursor postion + +VhostUserGpuCursorUpdate +^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + ----------------------------------------------------------------------------- + | VhostUserGpuCursorPos:pos | u32:hot_x | u32:hot_y | [u32; 64 * 64] cursor | + ----------------------------------------------------------------------------- + +- pos: the cursor location +- hot_x/hot_y: the cursor hot location +- cursor: RGBA cursor data + +VhostUserGpuScanout +^^^^^^^^^^^^^^^^^^^ + +:: + + ---------------------------------- + | u32:scanout-id | u32:w | u32:h | + ---------------------------------- + +- scanout-id: the scanout configuration to set +- w/h: the scanout width/height size + + +VhostUserGpuUpdate +^^^^^^^^^^^^^^^^^^ + +:: + + --------------------------------------------------------- + | u32:scanout-id | u32:x | u32:y | u32:w | u32:h | data | + --------------------------------------------------------- + +- scanout-id: the scanout content to update +- x/y/w/h: region of the update +- data: RGBA data (size is computed based on the region size, and request type) + +VhostUserGpuDMABUFScanout +^^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + --------------------------------------------------- + | u32:scanout-id | u32:x | u32:y | u32:w | u32:h | ... + ---------------------------------------------------------- + u32:fdw | u32:fwh | u32:stride | u32:flags | i32:fourcc | + ---------------------------------------------------------- + +- scanout-id: the scanout configuration to set +- x/y: the location of the scanout within the DMABUF +- w/h: the scanout width/height size +- fdw/fdh/stride/flags/fourcc: the DMABUF width/height/stride/flags/drm-fourcc + + +In QEMU the vhost-user-gpu message is implemented with the following struct: + +:: + + typedef struct VhostUserGpuMsg { + uint32_t request; /* VhostUserGpuRequest */ + uint32_t size; /* the following payload size */ + union { + VhostUserGpuCursorPos cursor_pos; + VhostUserGpuCursorUpdate cursor_update; + VhostUserGpuScanout scanout; + VhostUserGpuUpdate update; + VhostUserGpuDMABUFScanout dmabuf_scanout; + uint64_t u64; + } payload; + } QEMU_PACKED VhostUserGpuMsg; + +Protocol features +================= + +None yet. + +As the protocol may need to evolve, new messages and communication +changes are negotiated thanks to preliminary +VHOST_USER_GPU_GET_PROTOCOL_FEATURES and +VHOST_USER_GPU_SET_PROTOCOL_FEATURES requests. + +Message types +============= + +- VHOST_USER_GPU_GET_PROTOCOL_FEATURES + + Id:1 + Request payload: N/A + Reply payload: uint64_t + + Get the supported protocol features bitmask. + +- VHOST_USER_GPU_SET_PROTOCOL_FEATURES + + Id:2 + Request payload: uint64_t + Reply payload: N/A + + Enable protocol features using a bitmask. + +- VHOST_USER_GPU_GET_DISPLAY_INFO + + Id:3 + Request payload: N/A + Reply payload: struct virtio_gpu_resp_display_info (numbers in LE, + according to the virtio protocol) + + Get the preferred display configuration. + +- VHOST_USER_GPU_CURSOR_POS + + Id: 4 + Request payload: struct VhostUserGpuCursorPos + Reply payload: N/A + + Set/show the cursor position. + +- VHOST_USER_GPU_CURSOR_POS_HIDE + + Id:5 + Request payload: struct VhostUserGpuCursorPos + Reply payload: N/A + + Set/hide the cursor. + +- VHOST_USER_GPU_CURSOR_UPDATE + + Id:6 + Request payload: struct VhostUserGpuCursorUpdate + Reply payload: N/A + + Update the cursor shape and location. + +- VHOST_USER_GPU_SCANOUT + + Id:7 + Request payload: struct VhostUserGpuScanout + Reply payload: N/A + + Set the scanout resolution. To disable a scanout, the dimensions + width/height are set to 0. + +- VHOST_USER_GPU_UPDATE + + Id:8 + Request payload: struct VhostUserGpuUpdate + Reply payload: N/A + + Update the scanout content. The data payload contains the graphical bits. + The display should be flushed and presented. + +- VHOST_USER_GPU_DMABUF_SCANOUT + + Id:9 + Request payload: struct VhostUserGpuDMABUFScanout + Reply payload: N/A + + Set the scanout resolution/configuration, and share a DMABUF file + descriptor for the scanout content, which is passed as ancillary + data. To disable a scanout, the dimensions width/height are set + to 0, there is no file descriptor passed. + +- VHOST_USER_GPU_DMABUF_UPDATE + + Id:10 + Request payload: struct VhostUserGpuUpdate + Reply payload: u32 + + The display should be flushed and presented according to updated + region from VhostUserGpuUpdate. + + Note: there is no data payload, since the scanout is shared thanks + to DMABUF, that must have been set previously with + VHOST_USER_GPU_DMABUF_SCANOUT. diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt index 2efa44d124..40ba89675c 100644 --- a/docs/interop/vhost-user.txt +++ b/docs/interop/vhost-user.txt @@ -768,6 +768,14 @@ Master message types Ask vhost user input backend the list of virtio_input_config. + * VHOST_USER_GPU_SET_SOCKET + Id: TBD + Master payload: N/A + + Sets the GPU protocol socket file descriptor, which is passed as + ancillary data. The GPU protocol is used to inform the master of + rendering state and updates. See vhost-user-gpu.txt for details. + Slave message types ------------------- From patchwork Mon Jun 18 16:17:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931047 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418c6B61MGz9s1R for ; Tue, 19 Jun 2018 02:30:58 +1000 (AEST) Received: from localhost ([::1]:35800 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx3Q-0003NV-C5 for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:30:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44069) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrD-0002D9-3R for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwr6-0005Bi-QE for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:19 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45474 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwr6-0005BP-LX for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:12 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5A90C7DAC3 for ; Mon, 18 Jun 2018 16:18:12 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 09E04200AC23; Mon, 18 Jun 2018 16:18:11 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:19 +0200 Message-Id: <20180618161729.334-17-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:12 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:12 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 16/26] vhost-user: add vhost_user_gpu_get_num_capsets() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Marc-André Lureau --- contrib/libvhost-user/libvhost-user.h | 1 + include/hw/virtio/vhost-backend.h | 1 + hw/virtio/vhost-user.c | 15 +++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h index 9899bfda9e..b572071d61 100644 --- a/contrib/libvhost-user/libvhost-user.h +++ b/contrib/libvhost-user/libvhost-user.h @@ -93,6 +93,7 @@ typedef enum VhostUserRequest { VHOST_USER_POSTCOPY_END = 30, VHOST_USER_INPUT_GET_CONFIG, VHOST_USER_GPU_SET_SOCKET, + VHOST_USER_GPU_GET_NUM_CAPSETS, VHOST_USER_MAX } VhostUserRequest; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index daf9180c33..730e24c33b 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -164,5 +164,6 @@ int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev, int vhost_user_input_get_config(struct vhost_dev *dev, struct virtio_input_config **config); int vhost_user_gpu_set_socket(struct vhost_dev *dev, int fd); +int vhost_user_gpu_get_num_capsets(struct vhost_dev *dev, uint32_t *num); #endif /* VHOST_BACKEND_H */ diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 37864bc06a..8702027269 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -91,6 +91,7 @@ typedef enum VhostUserRequest { VHOST_USER_POSTCOPY_END = 30, VHOST_USER_INPUT_GET_CONFIG, VHOST_USER_GPU_SET_SOCKET, + VHOST_USER_GPU_GET_NUM_CAPSETS, VHOST_USER_MAX } VhostUserRequest; @@ -922,6 +923,20 @@ static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) return 0; } +int vhost_user_gpu_get_num_capsets(struct vhost_dev *dev, uint32_t *num) +{ + uint64_t u64; + + if (vhost_user_get_u64(dev, VHOST_USER_GPU_GET_NUM_CAPSETS, &u64) < 0) { + return -1; + } + if (u64 > UINT32_MAX) { + return -1; + } + *num = u64; + return 0; +} + static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features) { return vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features); From patchwork Mon Jun 18 16:17:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931051 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418c9X1RXmz9s1R for ; Tue, 19 Jun 2018 02:33:50 +1000 (AEST) Received: from localhost ([::1]:35814 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx6B-0005Mj-CL for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:33:47 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44085) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrE-0002EY-BJ for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwr8-0005Cx-Ad for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:20 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45476 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwr8-0005Cc-4a for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:14 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C8B267DAC3 for ; Mon, 18 Jun 2018 16:18:13 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 767BC2026D5B; Mon, 18 Jun 2018 16:18:13 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:20 +0200 Message-Id: <20180618161729.334-18-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:13 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:13 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 17/26] virtio: add virtio-gpu bswap helpers header X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Marc-André Lureau --- include/hw/virtio/virtio-gpu-bswap.h | 48 ++++++++++++++++++++++++++++ hw/display/virtio-gpu.c | 43 +------------------------ 2 files changed, 49 insertions(+), 42 deletions(-) create mode 100644 include/hw/virtio/virtio-gpu-bswap.h diff --git a/include/hw/virtio/virtio-gpu-bswap.h b/include/hw/virtio/virtio-gpu-bswap.h new file mode 100644 index 0000000000..bc9e895f9c --- /dev/null +++ b/include/hw/virtio/virtio-gpu-bswap.h @@ -0,0 +1,48 @@ +#ifndef HW_VIRTIO_GPU_BSWAP_H +#define HW_VIRTIO_GPU_BSWAP_H + +#include "qemu/bswap.h" + +static inline void +virtio_gpu_ctrl_hdr_bswap(struct virtio_gpu_ctrl_hdr *hdr) +{ + le32_to_cpus(&hdr->type); + le32_to_cpus(&hdr->flags); + le64_to_cpus(&hdr->fence_id); + le32_to_cpus(&hdr->ctx_id); + le32_to_cpus(&hdr->padding); +} + +static inline void +virtio_gpu_bswap_32(void *ptr, size_t size) +{ +#ifdef HOST_WORDS_BIGENDIAN + + size_t i; + struct virtio_gpu_ctrl_hdr *hdr = (struct virtio_gpu_ctrl_hdr *) ptr; + + virtio_gpu_ctrl_hdr_bswap(hdr); + + i = sizeof(struct virtio_gpu_ctrl_hdr); + while (i < size) { + le32_to_cpus((uint32_t *)(ptr + i)); + i = i + sizeof(uint32_t); + } + +#endif +} + +static inline void +virtio_gpu_t2d_bswap(struct virtio_gpu_transfer_to_host_2d *t2d) +{ + virtio_gpu_ctrl_hdr_bswap(&t2d->hdr); + le32_to_cpus(&t2d->r.x); + le32_to_cpus(&t2d->r.y); + le32_to_cpus(&t2d->r.width); + le32_to_cpus(&t2d->r.height); + le64_to_cpus(&t2d->offset); + le32_to_cpus(&t2d->resource_id); + le32_to_cpus(&t2d->padding); +} + +#endif diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 2dd3c3481a..6a55416be7 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -18,6 +18,7 @@ #include "trace.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-gpu-bswap.h" #include "hw/virtio/virtio-bus.h" #include "migration/blocker.h" #include "qemu/log.h" @@ -30,48 +31,6 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res); -static void -virtio_gpu_ctrl_hdr_bswap(struct virtio_gpu_ctrl_hdr *hdr) -{ - le32_to_cpus(&hdr->type); - le32_to_cpus(&hdr->flags); - le64_to_cpus(&hdr->fence_id); - le32_to_cpus(&hdr->ctx_id); - le32_to_cpus(&hdr->padding); -} - -static void virtio_gpu_bswap_32(void *ptr, - size_t size) -{ -#ifdef HOST_WORDS_BIGENDIAN - - size_t i; - struct virtio_gpu_ctrl_hdr *hdr = (struct virtio_gpu_ctrl_hdr *) ptr; - - virtio_gpu_ctrl_hdr_bswap(hdr); - - i = sizeof(struct virtio_gpu_ctrl_hdr); - while (i < size) { - le32_to_cpus((uint32_t *)(ptr + i)); - i = i + sizeof(uint32_t); - } - -#endif -} - -static void -virtio_gpu_t2d_bswap(struct virtio_gpu_transfer_to_host_2d *t2d) -{ - virtio_gpu_ctrl_hdr_bswap(&t2d->hdr); - le32_to_cpus(&t2d->r.x); - le32_to_cpus(&t2d->r.y); - le32_to_cpus(&t2d->r.width); - le32_to_cpus(&t2d->r.height); - le64_to_cpus(&t2d->offset); - le32_to_cpus(&t2d->resource_id); - le32_to_cpus(&t2d->padding); -} - #ifdef CONFIG_VIRGL #include #define VIRGL(_g, _virgl, _simple, ...) \ From patchwork Mon Jun 18 16:17:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931041 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418bzl6wb0z9s1R for ; Tue, 19 Jun 2018 02:25:23 +1000 (AEST) Received: from localhost ([::1]:35767 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwy1-00074D-HH for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:25:21 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44084) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrE-0002EX-BD for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwrA-0005DO-0H for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:20 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44994 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwr9-0005DE-R7 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:15 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7A375401EF03 for ; Mon, 18 Jun 2018 16:18:15 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0F1E3200AC23; Mon, 18 Jun 2018 16:18:14 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:21 +0200 Message-Id: <20180618161729.334-19-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:18:15 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:18:15 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 18/26] util: promote qemu_egl_rendernode_open() to libqemuutil X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" vhost-user-gpu will share the same code to open a DRM node. Signed-off-by: Marc-André Lureau --- include/qemu/drm.h | 6 +++++ ui/egl-helpers.c | 51 ++--------------------------------- util/drm.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ MAINTAINERS | 1 + util/Makefile.objs | 1 + 5 files changed, 76 insertions(+), 49 deletions(-) create mode 100644 include/qemu/drm.h create mode 100644 util/drm.c diff --git a/include/qemu/drm.h b/include/qemu/drm.h new file mode 100644 index 0000000000..4c3e622f5c --- /dev/null +++ b/include/qemu/drm.h @@ -0,0 +1,6 @@ +#ifndef QEMU_DRM_H_ +#define QEMU_DRM_H_ + +int qemu_drm_rendernode_open(const char *rendernode); + +#endif diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 16dc3ded36..472a8aa5f0 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -15,9 +15,7 @@ * License along with this library; if not, see . */ #include "qemu/osdep.h" -#include -#include - +#include "qemu/drm.h" #include "qemu/error-report.h" #include "ui/console.h" #include "ui/egl-helpers.h" @@ -146,57 +144,12 @@ int qemu_egl_rn_fd; struct gbm_device *qemu_egl_rn_gbm_dev; EGLContext qemu_egl_rn_ctx; -static int qemu_egl_rendernode_open(const char *rendernode) -{ - DIR *dir; - struct dirent *e; - int r, fd; - char *p; - - if (rendernode) { - return open(rendernode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); - } - - dir = opendir("/dev/dri"); - if (!dir) { - return -1; - } - - fd = -1; - while ((e = readdir(dir))) { - if (e->d_type != DT_CHR) { - continue; - } - - if (strncmp(e->d_name, "renderD", 7)) { - continue; - } - - p = g_strdup_printf("/dev/dri/%s", e->d_name); - - r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); - if (r < 0) { - g_free(p); - continue; - } - fd = r; - g_free(p); - break; - } - - closedir(dir); - if (fd < 0) { - return -1; - } - return fd; -} - int egl_rendernode_init(const char *rendernode) { qemu_egl_rn_fd = -1; int rc; - qemu_egl_rn_fd = qemu_egl_rendernode_open(rendernode); + qemu_egl_rn_fd = qemu_drm_rendernode_open(rendernode); if (qemu_egl_rn_fd == -1) { error_report("egl: no drm render node available"); goto err; diff --git a/util/drm.c b/util/drm.c new file mode 100644 index 0000000000..a23ff24538 --- /dev/null +++ b/util/drm.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015-2016 Gerd Hoffmann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "qemu/osdep.h" +#include "qemu/drm.h" + +#include +#include + +int qemu_drm_rendernode_open(const char *rendernode) +{ + DIR *dir; + struct dirent *e; + int r, fd; + char *p; + + if (rendernode) { + return open(rendernode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); + } + + dir = opendir("/dev/dri"); + if (!dir) { + return -1; + } + + fd = -1; + while ((e = readdir(dir))) { + if (e->d_type != DT_CHR) { + continue; + } + + if (strncmp(e->d_name, "renderD", 7)) { + continue; + } + + p = g_strdup_printf("/dev/dri/%s", e->d_name); + + r = open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); + if (r < 0) { + g_free(p); + continue; + } + fd = r; + g_free(p); + break; + } + + closedir(dir); + if (fd < 0) { + return -1; + } + return fd; +} diff --git a/MAINTAINERS b/MAINTAINERS index e5dee15967..42a5d46acd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1533,6 +1533,7 @@ S: Odd Fixes F: ui/ F: include/ui/ F: qapi/ui.json +F: util/drm.c Cocoa graphics M: Peter Maydell diff --git a/util/Makefile.objs b/util/Makefile.objs index e1c3fed4dc..1810f970ef 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -49,3 +49,4 @@ util-obj-y += stats64.o util-obj-y += systemd.o util-obj-y += iova-tree.o util-obj-$(CONFIG_LINUX) += vfio-helpers.o +util-obj-$(CONFIG_LINUX) += drm.o From patchwork Mon Jun 18 16:17:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931054 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418cHD1Ccmz9s2t for ; Tue, 19 Jun 2018 02:38:48 +1000 (AEST) Received: from localhost ([::1]:35870 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUxAz-0000jI-P9 for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:38:45 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44146) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrI-0002Gd-3O for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwrC-0005Eo-5P for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:24 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45480 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwrB-0005EN-Rs for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:18 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 827B47DAC3 for ; Mon, 18 Jun 2018 16:18:17 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9DAB52026D5B; Mon, 18 Jun 2018 16:18:16 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:22 +0200 Message-Id: <20180618161729.334-20-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:17 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:17 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 19/26] contrib: add vhost-user-gpu X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add a vhost-user gpu backend example, based on virtio-gpu/3d device. It is to be associated with a vhost-user-backend object, ex: -object vhost-user-backend,id=vug,cmd="vhost-user-gpu" TODO: - add/check multi-head support - stop/crash & resume handling - accelerated rendering/display to avoid the many round trips Signed-off-by: Marc-André Lureau --- contrib/vhost-user-gpu/drm.h | 63 ++ contrib/vhost-user-gpu/virgl.h | 25 + contrib/vhost-user-gpu/vugpu.h | 167 ++++ contrib/vhost-user-gpu/drm.c | 189 +++++ contrib/vhost-user-gpu/main.c | 1100 ++++++++++++++++++++++++++ contrib/vhost-user-gpu/virgl.c | 579 ++++++++++++++ MAINTAINERS | 2 + Makefile | 3 + Makefile.objs | 1 + configure | 32 + contrib/vhost-user-gpu/Makefile.objs | 10 + 11 files changed, 2171 insertions(+) create mode 100644 contrib/vhost-user-gpu/drm.h create mode 100644 contrib/vhost-user-gpu/virgl.h create mode 100644 contrib/vhost-user-gpu/vugpu.h create mode 100644 contrib/vhost-user-gpu/drm.c create mode 100644 contrib/vhost-user-gpu/main.c create mode 100644 contrib/vhost-user-gpu/virgl.c create mode 100644 contrib/vhost-user-gpu/Makefile.objs diff --git a/contrib/vhost-user-gpu/drm.h b/contrib/vhost-user-gpu/drm.h new file mode 100644 index 0000000000..ee95816cc9 --- /dev/null +++ b/contrib/vhost-user-gpu/drm.h @@ -0,0 +1,63 @@ +/* + * Virtio vhost-user GPU Device + * + * DRM helpers + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef VHOST_USER_GPU_DRM_H +#define VHOST_USER_GPU_DRM_H + +#include "qemu/osdep.h" + +#ifdef CONFIG_LIBDRM_INTEL +#include +#include +#endif + +struct drm_buffer; + +struct drm_device { + bool inited; + int fd; + char *name; +#ifdef CONFIG_LIBDRM_INTEL + drm_intel_bufmgr *bufmgr; +#endif + + bool (*alloc_bo)(struct drm_buffer *buf); + void (*free_bo)(struct drm_buffer *buf); + bool (*export_bo_to_prime)(struct drm_buffer *buf, int *fd); + bool (*map_bo)(struct drm_buffer *buf); + void (*unmap_bo)(struct drm_buffer *buf); + void (*device_destroy)(struct drm_device *dev); +}; + +struct drm_buffer { + struct drm_device *dev; + +#ifdef CONFIG_LIBDRM_INTEL + drm_intel_bo *intel_bo; +#endif /* HAVE_LIBDRM_INTEL */ + + uint32_t gem_handle; + int dmabuf_fd; + uint8_t *mmap; + + int width; + int height; + int bpp; + unsigned long stride; + int format; +}; + +bool drm_device_init(struct drm_device *dev, int fd); +void drm_device_destroy(struct drm_device *dev); + +bool drm_buffer_create(struct drm_buffer *buffer, struct drm_device *dev, + int width, int height); +bool drm_buffer_get_dmabuf_fd(struct drm_buffer *buffer, int *fd); +void drm_buffer_destroy(struct drm_buffer *buffer); + +#endif diff --git a/contrib/vhost-user-gpu/virgl.h b/contrib/vhost-user-gpu/virgl.h new file mode 100644 index 0000000000..f952bc9d4f --- /dev/null +++ b/contrib/vhost-user-gpu/virgl.h @@ -0,0 +1,25 @@ +/* + * Virtio vhost-user GPU Device + * + * Copyright Red Hat, Inc. 2013-2018 + * + * Authors: + * Dave Airlie + * Gerd Hoffmann + * Marc-André Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef VUGPU_VIRGL_H_ +#define VUGPU_VIRGL_H_ + +#include "vugpu.h" + +bool vg_virgl_init(VuGpu *g); +uint32_t vg_virgl_get_num_capsets(void); +void vg_virgl_process_cmd(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd); +void vg_virgl_update_cursor_data(VuGpu *g, uint32_t resource_id, + gpointer data); + +#endif diff --git a/contrib/vhost-user-gpu/vugpu.h b/contrib/vhost-user-gpu/vugpu.h new file mode 100644 index 0000000000..e691fb6f27 --- /dev/null +++ b/contrib/vhost-user-gpu/vugpu.h @@ -0,0 +1,167 @@ +/* + * Virtio vhost-user GPU Device + * + * Copyright Red Hat, Inc. 2013-2018 + * + * Authors: + * Dave Airlie + * Gerd Hoffmann + * Marc-André Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef VUGPU_H_ +#define VUGPU_H_ + +#include "contrib/libvhost-user/libvhost-user-glib.h" +#include "standard-headers/linux/virtio_gpu.h" + +#include "qemu/osdep.h" +#include "qemu/queue.h" +#include "qemu/iov.h" +#include "qemu/bswap.h" +#include "drm.h" + +typedef enum VhostUserGpuRequest { + VHOST_USER_GPU_NONE = 0, + VHOST_USER_GPU_GET_PROTOCOL_FEATURES, + VHOST_USER_GPU_SET_PROTOCOL_FEATURES, + VHOST_USER_GPU_GET_DISPLAY_INFO, + VHOST_USER_GPU_CURSOR_POS, + VHOST_USER_GPU_CURSOR_POS_HIDE, + VHOST_USER_GPU_CURSOR_UPDATE, + VHOST_USER_GPU_SCANOUT, + VHOST_USER_GPU_UPDATE, + VHOST_USER_GPU_DMABUF_SCANOUT, + VHOST_USER_GPU_DMABUF_UPDATE, +} VhostUserGpuRequest; + +typedef struct VhostUserGpuDisplayInfoReply { + struct virtio_gpu_resp_display_info info; +} VhostUserGpuDisplayInfoReply; + +typedef struct VhostUserGpuCursorPos { + uint32_t scanout_id; + uint32_t x; + uint32_t y; +} QEMU_PACKED VhostUserGpuCursorPos; + +typedef struct VhostUserGpuCursorUpdate { + VhostUserGpuCursorPos pos; + uint32_t hot_x; + uint32_t hot_y; + uint32_t data[64 * 64]; +} QEMU_PACKED VhostUserGpuCursorUpdate; + +typedef struct VhostUserGpuScanout { + uint32_t scanout_id; + uint32_t width; + uint32_t height; +} QEMU_PACKED VhostUserGpuScanout; + +typedef struct VhostUserGpuUpdate { + uint32_t scanout_id; + uint32_t x; + uint32_t y; + uint32_t width; + uint32_t height; + uint8_t data[]; +} QEMU_PACKED VhostUserGpuUpdate; + +typedef struct VhostUserGpuDMABUFScanout { + uint32_t scanout_id; + uint32_t x; + uint32_t y; + uint32_t width; + uint32_t height; + uint32_t fd_width; + uint32_t fd_height; + uint32_t fd_stride; + uint32_t fd_flags; + int fd_drm_fourcc; +} QEMU_PACKED VhostUserGpuDMABUFScanout; + +typedef struct VhostUserGpuMsg { + uint32_t request; /* VhostUserGpuRequest */ + uint32_t size; /* the following payload size */ + union { + VhostUserGpuCursorPos cursor_pos; + VhostUserGpuCursorUpdate cursor_update; + VhostUserGpuScanout scanout; + VhostUserGpuUpdate update; + VhostUserGpuDMABUFScanout dmabuf_scanout; + uint64_t u64; + } payload; +} QEMU_PACKED VhostUserGpuMsg; + +static VhostUserGpuMsg m __attribute__ ((unused)); +#define VHOST_USER_GPU_HDR_SIZE (sizeof(m.request) + sizeof(m.size)) + +struct virtio_gpu_scanout { + uint32_t width, height; + int x, y; + int invalidate; + uint32_t resource_id; +}; + +typedef struct VuGpu { + VugDev dev; + struct drm_device drm_dev; + int sock_fd; + int drm_rnode_fd; + GSource *renderer_source; + + bool virgl; + bool virgl_inited; + uint32_t inflight; + + struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS]; + QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist; + QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq; +} VuGpu; + +struct virtio_gpu_ctrl_command { + VuVirtqElement elem; + VuVirtq *vq; + struct virtio_gpu_ctrl_hdr cmd_hdr; + uint32_t error; + bool finished; + QTAILQ_ENTRY(virtio_gpu_ctrl_command) next; +}; + +#define VUGPU_FILL_CMD(out) do { \ + size_t s; \ + s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ + &out, sizeof(out)); \ + if (s != sizeof(out)) { \ + g_critical("%s: command size incorrect %zu vs %zu", \ + __func__, s, sizeof(out)); \ + return; \ + } \ + } while (0) + + +void vg_ctrl_response(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd, + struct virtio_gpu_ctrl_hdr *resp, + size_t resp_len); + +void vg_ctrl_response_nodata(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd, + enum virtio_gpu_ctrl_type type); + +int vg_create_mapping_iov(VuGpu *g, + struct virtio_gpu_resource_attach_backing *ab, + struct virtio_gpu_ctrl_command *cmd, + struct iovec **iov); + +void vg_get_display_info(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd); + +void vg_wait_ok(VuGpu *g); + +void vg_send_msg(VuGpu *g, const VhostUserGpuMsg *msg, int fd); + +void vg_sock_fd_read(int sock, void *buf, ssize_t buflen); + +#endif diff --git a/contrib/vhost-user-gpu/drm.c b/contrib/vhost-user-gpu/drm.c new file mode 100644 index 0000000000..143cdea694 --- /dev/null +++ b/contrib/vhost-user-gpu/drm.c @@ -0,0 +1,189 @@ +/* + * Virtio vhost-user GPU Device + * + * DRM helpers + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include /* not much to do with xf86 */ +#include + +#include "drm.h" + +#ifdef CONFIG_LIBDRM_INTEL +static bool +intel_alloc_bo(struct drm_buffer *buf) +{ + uint32_t tiling = I915_TILING_NONE; + + buf->intel_bo = drm_intel_bo_alloc_tiled(buf->dev->bufmgr, "vhost-user-gpu", + buf->width, buf->height, + (buf->bpp / 8), &tiling, + &buf->stride, 0); + + if (!buf->intel_bo) { + return false; + } + + if (tiling != I915_TILING_NONE) { + drm_intel_bo_unreference(buf->intel_bo); + return false; + } + + return true; +} + +static void +intel_free_bo(struct drm_buffer *buf) +{ + drm_intel_bo_unreference(buf->intel_bo); +} + +static bool +intel_map_bo(struct drm_buffer *buf) +{ + if (drm_intel_gem_bo_map_gtt(buf->intel_bo) != 0) { + return false; + } + + buf->mmap = buf->intel_bo->virtual; + + return true; +} + +static bool +intel_export_bo_to_prime(struct drm_buffer *buffer, int *fd) +{ + if (drm_intel_bo_gem_export_to_prime(buffer->intel_bo, fd) < 0) { + return false; + } + + return true; +} + +static void +intel_unmap_bo(struct drm_buffer *buf) +{ + drm_intel_gem_bo_unmap_gtt(buf->intel_bo); +} + +static void +intel_device_destroy(struct drm_device *dev) +{ + drm_intel_bufmgr_destroy(dev->bufmgr); +} + +#endif /* CONFIG_LIBDRM_INTEL */ + +void +drm_device_destroy(struct drm_device *dev) +{ + if (!dev->inited) { + return; + } + + dev->device_destroy(dev); +} + +bool +drm_device_init(struct drm_device *dev, int fd) +{ + drmVersionPtr version = drmGetVersion(fd); + + dev->fd = fd; + dev->name = strdup(version->name); + + if (0) { + /* nothing */ + } +#ifdef CONFIG_LIBDRM_INTEL + else if (!strcmp(dev->name, "i915")) { + dev->bufmgr = drm_intel_bufmgr_gem_init(fd, 32); + if (!dev->bufmgr) { + return false; + } + dev->alloc_bo = intel_alloc_bo; + dev->free_bo = intel_free_bo; + dev->export_bo_to_prime = intel_export_bo_to_prime; + dev->map_bo = intel_map_bo; + dev->unmap_bo = intel_unmap_bo; + dev->device_destroy = intel_device_destroy; + } +#endif + else { + g_warning("Error: drm device %s unsupported.", dev->name); + return false; + } + + dev->inited = true; + return true; +} + +static bool +drm_buffer_map(struct drm_buffer *buf) +{ + struct drm_device *dev = buf->dev; + + return dev->map_bo(buf); +} + +static void +drm_buffer_unmap(struct drm_buffer *buf) +{ + struct drm_device *dev = buf->dev; + + dev->unmap_bo(buf); +} + +bool +drm_buffer_get_dmabuf_fd(struct drm_buffer *buffer, int *fd) +{ + if (!buffer->dev->export_bo_to_prime(buffer, fd)) { + g_warning("gem_export_to_prime failed"); + return false; + } + + if (*fd < 0) { + g_warning("error: dmabuf_fd < 0"); + return false; + } + + return true; +} + +bool +drm_buffer_create(struct drm_buffer *buffer, struct drm_device *dev, + int width, int height) +{ + buffer->dev = dev; + buffer->width = width; + buffer->height = height; + buffer->bpp = 32; + buffer->format = DRM_FORMAT_XRGB8888; + if (!dev->alloc_bo(buffer)) { + g_warning("alloc_bo failed"); + return false; + } + + if (!drm_buffer_map(buffer)) { + g_warning("map_bo failed"); + goto err; + } + + return true; + +err: + dev->free_bo(buffer); + return false; +} + +void +drm_buffer_destroy(struct drm_buffer *buffer) +{ + struct drm_device *drm_dev = buffer->dev; + + drm_buffer_unmap(buffer); + drm_dev->free_bo(buffer); +} diff --git a/contrib/vhost-user-gpu/main.c b/contrib/vhost-user-gpu/main.c new file mode 100644 index 0000000000..0ec76900ee --- /dev/null +++ b/contrib/vhost-user-gpu/main.c @@ -0,0 +1,1100 @@ +/* + * Virtio vhost-user GPU Device + * + * Copyright Red Hat, Inc. 2013-2018 + * + * Authors: + * Dave Airlie + * Gerd Hoffmann + * Marc-André Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "qemu/osdep.h" +#include "qemu/drm.h" + +#include + +#include "vugpu.h" +#include "hw/virtio/virtio-gpu-bswap.h" +#include "virgl.h" + +struct virtio_gpu_simple_resource { + uint32_t resource_id; + uint32_t width; + uint32_t height; + uint32_t format; + struct iovec *iov; + unsigned int iov_cnt; + uint32_t scanout_bitmask; + pixman_image_t *image; + struct drm_buffer drm_buffer; + QTAILQ_ENTRY(virtio_gpu_simple_resource) next; +}; + +static char *opt_socket_path; +static char *opt_render_node; +static gboolean opt_virgl; + +static const char * +vg_cmd_to_string(int cmd) +{ +#define CMD(cmd) [cmd] = #cmd + static const char *vg_cmd_str[] = { + CMD(VIRTIO_GPU_UNDEFINED), + + /* 2d commands */ + CMD(VIRTIO_GPU_CMD_GET_DISPLAY_INFO), + CMD(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D), + CMD(VIRTIO_GPU_CMD_RESOURCE_UNREF), + CMD(VIRTIO_GPU_CMD_SET_SCANOUT), + CMD(VIRTIO_GPU_CMD_RESOURCE_FLUSH), + CMD(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D), + CMD(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING), + CMD(VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING), + CMD(VIRTIO_GPU_CMD_GET_CAPSET_INFO), + CMD(VIRTIO_GPU_CMD_GET_CAPSET), + + /* 3d commands */ + CMD(VIRTIO_GPU_CMD_CTX_CREATE), + CMD(VIRTIO_GPU_CMD_CTX_DESTROY), + CMD(VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE), + CMD(VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE), + CMD(VIRTIO_GPU_CMD_RESOURCE_CREATE_3D), + CMD(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D), + CMD(VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D), + CMD(VIRTIO_GPU_CMD_SUBMIT_3D), + + /* cursor commands */ + CMD(VIRTIO_GPU_CMD_UPDATE_CURSOR), + CMD(VIRTIO_GPU_CMD_MOVE_CURSOR), + }; +#undef REQ + + if (cmd >= 0 && cmd < G_N_ELEMENTS(vg_cmd_str)) { + return vg_cmd_str[cmd]; + } else { + return "unknown"; + } +} + +void +vg_sock_fd_read(int sock, void *buf, ssize_t buflen) +{ + int ret; + + do { + ret = read(sock, buf, buflen); + } while (ret < 0 && (errno == EINTR || errno == EAGAIN)); + + g_warn_if_fail(ret == buflen); +} + +void +vg_wait_ok(VuGpu *g) +{ + uint32_t ok; + + vg_sock_fd_read(g->sock_fd, &ok, sizeof(ok)); +} + +static void +vg_sock_fd_write(int sock, const void *buf, ssize_t buflen, int fd) +{ + ssize_t ret; + struct msghdr msg; + struct iovec iov; + union { + struct cmsghdr cmsghdr; + char control[CMSG_SPACE(sizeof(int))]; + } cmsgu; + struct cmsghdr *cmsg; + + iov.iov_base = (void *)buf; + iov.iov_len = buflen; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + if (fd != -1) { + msg.msg_control = cmsgu.control; + msg.msg_controllen = sizeof(cmsgu.control); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + *((int *)CMSG_DATA(cmsg)) = fd; + } else { + msg.msg_control = NULL; + msg.msg_controllen = 0; + } + + do { + ret = sendmsg(sock, &msg, 0); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + + g_warn_if_fail(ret == buflen); +} + +void +vg_send_msg(VuGpu *vg, const VhostUserGpuMsg *msg, int fd) +{ + vg_sock_fd_write(vg->sock_fd, msg, VHOST_USER_GPU_HDR_SIZE + msg->size, fd); +} + +static struct virtio_gpu_simple_resource * +virtio_gpu_find_resource(VuGpu *g, uint32_t resource_id) +{ + struct virtio_gpu_simple_resource *res; + + QTAILQ_FOREACH(res, &g->reslist, next) { + if (res->resource_id == resource_id) { + return res; + } + } + return NULL; +} + +void +vg_ctrl_response(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd, + struct virtio_gpu_ctrl_hdr *resp, + size_t resp_len) +{ + size_t s; + + if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE) { + resp->flags |= VIRTIO_GPU_FLAG_FENCE; + resp->fence_id = cmd->cmd_hdr.fence_id; + resp->ctx_id = cmd->cmd_hdr.ctx_id; + } + virtio_gpu_ctrl_hdr_bswap(resp); + s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len); + if (s != resp_len) { + g_critical("%s: response size incorrect %zu vs %zu", + __func__, s, resp_len); + } + vu_queue_push(&g->dev.parent, cmd->vq, &cmd->elem, s); + vu_queue_notify(&g->dev.parent, cmd->vq); + cmd->finished = true; +} + +void +vg_ctrl_response_nodata(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd, + enum virtio_gpu_ctrl_type type) +{ + struct virtio_gpu_ctrl_hdr resp = { + .type = type, + }; + + vg_ctrl_response(g, cmd, &resp, sizeof(resp)); +} + +void +vg_get_display_info(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resp_display_info dpy_info = { 0 ,}; + VhostUserGpuMsg msg = { + .request = VHOST_USER_GPU_GET_DISPLAY_INFO, + .size = 0, + }; + + vg_send_msg(vg, &msg, -1); + vg_sock_fd_read(vg->sock_fd, &dpy_info, sizeof(dpy_info)); + + vg_ctrl_response(vg, cmd, &dpy_info.hdr, sizeof(dpy_info)); +} + +static pixman_format_code_t +get_pixman_format(uint32_t virtio_gpu_format) +{ + switch (virtio_gpu_format) { +#ifdef HOST_WORDS_BIGENDIAN + case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: + return PIXMAN_b8g8r8x8; + case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: + return PIXMAN_b8g8r8a8; + case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: + return PIXMAN_x8r8g8b8; + case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: + return PIXMAN_a8r8g8b8; + case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: + return PIXMAN_r8g8b8x8; + case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: + return PIXMAN_r8g8b8a8; + case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: + return PIXMAN_x8b8g8r8; + case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: + return PIXMAN_a8b8g8r8; +#else + case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM: + return PIXMAN_x8r8g8b8; + case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM: + return PIXMAN_a8r8g8b8; + case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM: + return PIXMAN_b8g8r8x8; + case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM: + return PIXMAN_b8g8r8a8; + case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM: + return PIXMAN_x8b8g8r8; + case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM: + return PIXMAN_a8b8g8r8; + case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM: + return PIXMAN_r8g8b8x8; + case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM: + return PIXMAN_r8g8b8a8; +#endif + default: + return 0; + } +} + +static void +vg_resource_create_2d(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + pixman_format_code_t pformat; + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_create_2d c2d; + + VUGPU_FILL_CMD(c2d); + virtio_gpu_bswap_32(&c2d, sizeof(c2d)); + + if (c2d.resource_id == 0) { + g_critical("%s: resource id 0 is not allowed", __func__); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + res = virtio_gpu_find_resource(g, c2d.resource_id); + if (res) { + g_critical("%s: resource already exists %d", __func__, c2d.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + res = g_new0(struct virtio_gpu_simple_resource, 1); + res->width = c2d.width; + res->height = c2d.height; + res->format = c2d.format; + res->resource_id = c2d.resource_id; + + pformat = get_pixman_format(c2d.format); + if (!pformat) { + g_critical("%s: host couldn't handle guest format %d", + __func__, c2d.format); + g_free(res); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + drm_buffer_create(&res->drm_buffer, &g->drm_dev, c2d.width, c2d.height); + res->image = pixman_image_create_bits(pformat, + c2d.width, + c2d.height, + (uint32_t *)res->drm_buffer.mmap, + res->drm_buffer.stride); + if (!res->image) { + g_critical("%s: resource creation failed %d %d %d", + __func__, c2d.resource_id, c2d.width, c2d.height); + g_free(res); + cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; + return; + } + + QTAILQ_INSERT_HEAD(&g->reslist, res, next); +} + +static void +vg_resource_destroy(VuGpu *g, + struct virtio_gpu_simple_resource *res) +{ + drm_buffer_destroy(&res->drm_buffer); + pixman_image_unref(res->image); + QTAILQ_REMOVE(&g->reslist, res, next); + g_free(res); +} + +static void +vg_resource_unref(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_unref unref; + + VUGPU_FILL_CMD(unref); + virtio_gpu_bswap_32(&unref, sizeof(unref)); + + res = virtio_gpu_find_resource(g, unref.resource_id); + if (!res) { + g_critical("%s: illegal resource specified %d", + __func__, unref.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + vg_resource_destroy(g, res); +} + +int +vg_create_mapping_iov(VuGpu *g, + struct virtio_gpu_resource_attach_backing *ab, + struct virtio_gpu_ctrl_command *cmd, + struct iovec **iov) +{ + struct virtio_gpu_mem_entry *ents; + size_t esize, s; + int i; + + if (ab->nr_entries > 16384) { + g_critical("%s: nr_entries is too big (%d > 16384)", + __func__, ab->nr_entries); + return -1; + } + + esize = sizeof(*ents) * ab->nr_entries; + ents = g_malloc(esize); + s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, + sizeof(*ab), ents, esize); + if (s != esize) { + g_critical("%s: command data size incorrect %zu vs %zu", + __func__, s, esize); + g_free(ents); + return -1; + } + + *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries); + for (i = 0; i < ab->nr_entries; i++) { + uint64_t len = ents[i].length; + (*iov)[i].iov_len = ents[i].length; + (*iov)[i].iov_base = vu_gpa_to_va(&g->dev.parent, &len, ents[i].addr); + if (!(*iov)[i].iov_base || len != ents[i].length) { + g_critical("%s: resource %d element %d", + __func__, ab->resource_id, i); + g_free(*iov); + g_free(ents); + *iov = NULL; + return -1; + } + } + g_free(ents); + return 0; +} + +static void +vg_resource_attach_backing(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_attach_backing ab; + int ret; + + VUGPU_FILL_CMD(ab); + virtio_gpu_bswap_32(&ab, sizeof(ab)); + + res = virtio_gpu_find_resource(g, ab.resource_id); + if (!res) { + g_critical("%s: illegal resource specified %d", + __func__, ab.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + ret = vg_create_mapping_iov(g, &ab, cmd, &res->iov); + if (ret != 0) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + return; + } + + res->iov_cnt = ab.nr_entries; +} + +static void +vg_resource_detach_backing(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_detach_backing detach; + + VUGPU_FILL_CMD(detach); + virtio_gpu_bswap_32(&detach, sizeof(detach)); + + res = virtio_gpu_find_resource(g, detach.resource_id); + if (!res || !res->iov) { + g_critical("%s: illegal resource specified %d", + __func__, detach.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + g_free(res->iov); + res->iov = NULL; + res->iov_cnt = 0; +} + +static void +vg_transfer_to_host_2d(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + int h; + uint32_t src_offset, dst_offset, stride; + int bpp; + pixman_format_code_t format; + struct virtio_gpu_transfer_to_host_2d t2d; + + VUGPU_FILL_CMD(t2d); + virtio_gpu_t2d_bswap(&t2d); + + res = virtio_gpu_find_resource(g, t2d.resource_id); + if (!res || !res->iov) { + g_critical("%s: illegal resource specified %d", + __func__, t2d.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + if (t2d.r.x > res->width || + t2d.r.y > res->height || + t2d.r.width > res->width || + t2d.r.height > res->height || + t2d.r.x + t2d.r.width > res->width || + t2d.r.y + t2d.r.height > res->height) { + g_critical("%s: transfer bounds outside resource" + " bounds for resource %d: %d %d %d %d vs %d %d", + __func__, t2d.resource_id, t2d.r.x, t2d.r.y, + t2d.r.width, t2d.r.height, res->width, res->height); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + format = pixman_image_get_format(res->image); + bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8; + stride = pixman_image_get_stride(res->image); + + if (t2d.offset || t2d.r.x || t2d.r.y || + t2d.r.width != pixman_image_get_width(res->image)) { + void *img_data = pixman_image_get_data(res->image); + for (h = 0; h < t2d.r.height; h++) { + src_offset = t2d.offset + stride * h; + dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp); + + iov_to_buf(res->iov, res->iov_cnt, src_offset, + img_data + + dst_offset, t2d.r.width * bpp); + } + } else { + iov_to_buf(res->iov, res->iov_cnt, 0, + pixman_image_get_data(res->image), + pixman_image_get_stride(res->image) + * pixman_image_get_height(res->image)); + } +} + +static void +vg_set_scanout(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_scanout *scanout; + struct virtio_gpu_set_scanout ss; + + VUGPU_FILL_CMD(ss); + virtio_gpu_bswap_32(&ss, sizeof(ss)); + + if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUTS) { + g_critical("%s: illegal scanout id specified %d", + __func__, ss.scanout_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + + if (ss.resource_id == 0) { + scanout = &g->scanout[ss.scanout_id]; + if (scanout->resource_id) { + res = virtio_gpu_find_resource(g, scanout->resource_id); + if (res) { + res->scanout_bitmask &= ~(1 << ss.scanout_id); + } + } + if (ss.scanout_id == 0) { + g_critical("%s: illegal scanout id specified %d", + __func__, ss.scanout_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + scanout->width = 0; + scanout->height = 0; + return; + } + + /* create a surface for this scanout */ + res = virtio_gpu_find_resource(g, ss.resource_id); + if (!res) { + g_critical("%s: illegal resource specified %d", + __func__, ss.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + if (ss.r.x > res->width || + ss.r.y > res->height || + ss.r.width > res->width || + ss.r.height > res->height || + ss.r.x + ss.r.width > res->width || + ss.r.y + ss.r.height > res->height) { + g_critical("%s: illegal scanout %d bounds for" + " resource %d, (%d,%d)+%d,%d vs %d %d", + __func__, ss.scanout_id, ss.resource_id, ss.r.x, ss.r.y, + ss.r.width, ss.r.height, res->width, res->height); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + scanout = &g->scanout[ss.scanout_id]; + + res->scanout_bitmask |= (1 << ss.scanout_id); + scanout->resource_id = ss.resource_id; + scanout->x = ss.r.x; + scanout->y = ss.r.y; + scanout->width = ss.r.width; + scanout->height = ss.r.height; + + if (res->drm_buffer.mmap) { + struct drm_buffer *buffer = &res->drm_buffer; + VhostUserGpuMsg msg = { + .request = VHOST_USER_GPU_DMABUF_SCANOUT, + .size = sizeof(VhostUserGpuDMABUFScanout), + .payload.dmabuf_scanout.scanout_id = ss.scanout_id, + .payload.dmabuf_scanout.x = ss.r.x, + .payload.dmabuf_scanout.y = ss.r.y, + .payload.dmabuf_scanout.width = ss.r.width, + .payload.dmabuf_scanout.height = ss.r.height, + .payload.dmabuf_scanout.fd_width = buffer->width, + .payload.dmabuf_scanout.fd_height = buffer->height, + .payload.dmabuf_scanout.fd_stride = buffer->stride, + .payload.dmabuf_scanout.fd_drm_fourcc = buffer->format + }; + int fd; + + if (drm_buffer_get_dmabuf_fd(buffer, &fd)) { + vg_send_msg(g, &msg, fd); + close(fd); + } + } else { + VhostUserGpuMsg msg = { + .request = VHOST_USER_GPU_SCANOUT, + .size = sizeof(VhostUserGpuScanout), + .payload.scanout.scanout_id = ss.scanout_id, + .payload.scanout.width = scanout->width, + .payload.scanout.height = scanout->height + }; + vg_send_msg(g, &msg, -1); + } +} + +static void +vg_resource_flush(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_simple_resource *res; + struct virtio_gpu_resource_flush rf; + pixman_region16_t flush_region; + int i; + + VUGPU_FILL_CMD(rf); + virtio_gpu_bswap_32(&rf, sizeof(rf)); + + res = virtio_gpu_find_resource(g, rf.resource_id); + if (!res) { + g_critical("%s: illegal resource specified %d\n", + __func__, rf.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + if (rf.r.x > res->width || + rf.r.y > res->height || + rf.r.width > res->width || + rf.r.height > res->height || + rf.r.x + rf.r.width > res->width || + rf.r.y + rf.r.height > res->height) { + g_critical("%s: flush bounds outside resource" + " bounds for resource %d: %d %d %d %d vs %d %d\n", + __func__, rf.resource_id, rf.r.x, rf.r.y, + rf.r.width, rf.r.height, res->width, res->height); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + pixman_region_init_rect(&flush_region, + rf.r.x, rf.r.y, rf.r.width, rf.r.height); + for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) { + struct virtio_gpu_scanout *scanout; + pixman_region16_t region, finalregion; + pixman_box16_t *extents; + + if (!(res->scanout_bitmask & (1 << i))) { + continue; + } + scanout = &g->scanout[i]; + + pixman_region_init(&finalregion); + pixman_region_init_rect(®ion, scanout->x, scanout->y, + scanout->width, scanout->height); + + pixman_region_intersect(&finalregion, &flush_region, ®ion); + + extents = pixman_region_extents(&finalregion); + size_t width = extents->x2 - extents->x1; + size_t height = extents->y2 - extents->y1; + + if (res->drm_buffer.mmap) { + VhostUserGpuMsg vmsg = { + .request = VHOST_USER_GPU_DMABUF_UPDATE, + .size = sizeof(VhostUserGpuUpdate), + .payload.update.scanout_id = i, + .payload.update.x = extents->x1, + .payload.update.y = extents->y1, + .payload.update.width = width, + .payload.update.height = height + }; + vg_send_msg(g, &vmsg, -1); + vg_wait_ok(g); + } else { + size_t bpp = + PIXMAN_FORMAT_BPP(pixman_image_get_format(res->image)) / 8; + size_t size = width * height * bpp; + + VhostUserGpuMsg *msg = g_malloc(VHOST_USER_GPU_HDR_SIZE + + sizeof(VhostUserGpuUpdate) + size); + msg->request = VHOST_USER_GPU_UPDATE; + msg->size = sizeof(VhostUserGpuUpdate) + size; + msg->payload.update.scanout_id = i; + msg->payload.update.x = extents->x1; + msg->payload.update.y = extents->y1; + msg->payload.update.width = width; + msg->payload.update.height = height; + pixman_image_t *i = + pixman_image_create_bits(pixman_image_get_format(res->image), + msg->payload.update.width, + msg->payload.update.height, + (uint32_t *)msg->payload.update.data, + width * bpp); + pixman_image_composite(PIXMAN_OP_SRC, + res->image, NULL, i, + extents->x1, extents->y1, + 0, 0, 0, 0, + width, height); + pixman_image_unref(i); + vg_send_msg(g, msg, -1); + g_free(msg); + } + pixman_region_fini(®ion); + pixman_region_fini(&finalregion); + } + pixman_region_fini(&flush_region); +} + +static void +vg_process_cmd(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd) +{ + switch (cmd->cmd_hdr.type) { + case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: + vg_get_display_info(vg, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: + vg_resource_create_2d(vg, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_UNREF: + vg_resource_unref(vg, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_FLUSH: + vg_resource_flush(vg, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: + vg_transfer_to_host_2d(vg, cmd); + break; + case VIRTIO_GPU_CMD_SET_SCANOUT: + vg_set_scanout(vg, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: + vg_resource_attach_backing(vg, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: + vg_resource_detach_backing(vg, cmd); + break; + default: + g_warning("TODO handle ctrl %x\n", cmd->cmd_hdr.type); + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + break; + } + if (!cmd->finished) { + vg_ctrl_response_nodata(vg, cmd, cmd->error ? cmd->error : + VIRTIO_GPU_RESP_OK_NODATA); + } +} + +static void +vg_handle_ctrl(VuDev *dev, int qidx) +{ + VuGpu *vg = container_of(dev, VuGpu, dev.parent); + VuVirtq *vq = vu_get_queue(dev, qidx); + struct virtio_gpu_ctrl_command *cmd = NULL; + size_t len; + + for (;;) { + cmd = vu_queue_pop(dev, vq, sizeof(struct virtio_gpu_ctrl_command)); + if (!cmd) { + break; + } + cmd->vq = vq; + cmd->error = 0; + cmd->finished = false; + + len = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, + 0, &cmd->cmd_hdr, sizeof(cmd->cmd_hdr)); + if (len != sizeof(cmd->cmd_hdr)) { + g_warning("%s: command size incorrect %zu vs %zu\n", + __func__, len, sizeof(cmd->cmd_hdr)); + } + + virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr); + g_debug("%d %s\n", cmd->cmd_hdr.type, + vg_cmd_to_string(cmd->cmd_hdr.type)); + + if (vg->virgl) { + vg_virgl_process_cmd(vg, cmd); + } else { + vg_process_cmd(vg, cmd); + } + + if (!cmd->finished) { + QTAILQ_INSERT_TAIL(&vg->fenceq, cmd, next); + vg->inflight++; + } else { + g_free(cmd); + } + } +} + +static void +update_cursor_data_simple(VuGpu *g, uint32_t resource_id, gpointer data) +{ + struct virtio_gpu_simple_resource *res; + + res = virtio_gpu_find_resource(g, resource_id); + g_return_if_fail(res != NULL); + g_return_if_fail(pixman_image_get_width(res->image) == 64); + g_return_if_fail(pixman_image_get_height(res->image) == 64); + g_return_if_fail( + PIXMAN_FORMAT_BPP(pixman_image_get_format(res->image)) == 32); + + memcpy(data, pixman_image_get_data(res->image), 64 * 64 * sizeof(uint32_t)); +} + +static void +vg_process_cursor_cmd(VuGpu *g, struct virtio_gpu_update_cursor *cursor) +{ + bool move = cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR; + + g_debug("%s move:%d\n", G_STRFUNC, move); + + if (move) { + VhostUserGpuMsg msg = { + .request = cursor->resource_id ? + VHOST_USER_GPU_CURSOR_POS : VHOST_USER_GPU_CURSOR_POS_HIDE, + .size = sizeof(VhostUserGpuCursorPos), + .payload.cursor_pos = { + .scanout_id = cursor->pos.scanout_id, + .x = cursor->pos.x, + .y = cursor->pos.y, + } + }; + vg_send_msg(g, &msg, -1); + } else { + VhostUserGpuMsg msg = { + .request = VHOST_USER_GPU_CURSOR_UPDATE, + .size = sizeof(VhostUserGpuCursorUpdate), + .payload.cursor_update = { + .pos = { + .scanout_id = cursor->pos.scanout_id, + .x = cursor->pos.x, + .y = cursor->pos.y, + }, + .hot_x = cursor->hot_x, + .hot_y = cursor->hot_y, + } + }; + if (g->virgl) { + vg_virgl_update_cursor_data(g, cursor->resource_id, + msg.payload.cursor_update.data); + } else { + update_cursor_data_simple(g, cursor->resource_id, + msg.payload.cursor_update.data); + } + vg_send_msg(g, &msg, -1); + } +} + +static void +vg_handle_cursor(VuDev *dev, int qidx) +{ + VuGpu *g = container_of(dev, VuGpu, dev.parent); + VuVirtq *vq = vu_get_queue(dev, qidx); + VuVirtqElement *elem; + size_t len; + struct virtio_gpu_update_cursor cursor; + + for (;;) { + elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); + if (!elem) { + break; + } + g_debug("cursor out:%d in:%d\n", elem->out_num, elem->in_num); + + len = iov_to_buf(elem->out_sg, elem->out_num, + 0, &cursor, sizeof(cursor)); + if (len != sizeof(cursor)) { + g_warning("%s: cursor size incorrect %zu vs %zu\n", + __func__, len, sizeof(cursor)); + } else { + virtio_gpu_bswap_32(&cursor, sizeof(cursor)); + vg_process_cursor_cmd(g, &cursor); + } + vu_queue_push(dev, vq, elem, 0); + vu_queue_notify(dev, vq); + g_free(elem); + } +} + +static void +vg_panic(VuDev *dev, const char *msg) +{ + g_critical("%s\n", msg); + exit(1); +} + +static void +vg_queue_set_started(VuDev *dev, int qidx, bool started) +{ + VuVirtq *vq = vu_get_queue(dev, qidx); + + g_debug("queue started %d:%d\n", qidx, started); + + switch (qidx) { + case 0: + vu_set_queue_handler(dev, vq, started ? vg_handle_ctrl : NULL); + break; + case 1: + vu_set_queue_handler(dev, vq, started ? vg_handle_cursor : NULL); + break; + default: + break; + } +} + +static void +set_protocol_features(VuGpu *g) +{ + uint64_t u64; + VhostUserGpuMsg msg = { + .request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES + }; + + vg_send_msg(g, &msg, -1); + vg_sock_fd_read(g->sock_fd, &u64, sizeof(u64)); + msg = (VhostUserGpuMsg) { + .request = VHOST_USER_GPU_SET_PROTOCOL_FEATURES, + .size = sizeof(uint64_t), + .payload.u64 = 0 + }; + vg_send_msg(g, &msg, -1); +} + +static int +vg_process_msg(VuDev *dev, VhostUserMsg *msg, int *do_reply) +{ + VuGpu *g = container_of(dev, VuGpu, dev.parent); + + switch (msg->request) { + case VHOST_USER_GPU_SET_SOCKET: { + g_return_val_if_fail(msg->fd_num == 1, 1); + g_return_val_if_fail(g->sock_fd == -1, 1); + g->sock_fd = msg->fds[0]; + set_protocol_features(g); + return 1; + } + case VHOST_USER_GPU_GET_NUM_CAPSETS: + g_return_val_if_fail(msg->fd_num == 0, 1); + msg->payload.u64 = vg_virgl_get_num_capsets(); + msg->size = sizeof(msg->payload.u64); + *do_reply = true; + return 1; + default: + return 0; + } + + return 0; +} + +static uint64_t +vg_get_features(VuDev *dev) +{ + uint64_t features = 0; + + if (opt_virgl) { + features |= 1 << VIRTIO_GPU_F_VIRGL; + } + + return features; +} + +static void +vg_set_features(VuDev *dev, uint64_t features) +{ + VuGpu *g = container_of(dev, VuGpu, dev.parent); + bool virgl = features & (1 << VIRTIO_GPU_F_VIRGL); + + if (virgl && !g->virgl_inited) { + if (!vg_virgl_init(g)) { + vg_panic(dev, "Failed to initialize virgl"); + } + g->virgl_inited = true; + } + + g->virgl = virgl; +} + +static const VuDevIface vuiface = { + .set_features = vg_set_features, + .get_features = vg_get_features, + .queue_set_started = vg_queue_set_started, + .process_msg = vg_process_msg, +}; + +static void +vg_destroy(VuGpu *g) +{ + struct virtio_gpu_simple_resource *res, *tmp; + + vug_deinit(&g->dev); + + if (g->sock_fd != -1) { + close(g->sock_fd); + g->sock_fd = -1; + } + + QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { + vg_resource_destroy(g, res); + } + + drm_device_destroy(&g->drm_dev); +} + +static int unix_sock_new(char *path) +{ + int sock; + struct sockaddr_un un; + size_t len; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock <= 0) { + perror("socket"); + return -1; + } + + un.sun_family = AF_UNIX; + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + len = sizeof(un.sun_family) + strlen(un.sun_path); + + unlink(path); + if (bind(sock, (struct sockaddr *)&un, len) < 0) { + perror("bind"); + goto fail; + } + + if (listen(sock, 1) < 0) { + perror("listen"); + goto fail; + } + + return sock; + +fail: + close(sock); + + return -1; +} + +static GOptionEntry entries[] = { + { "socket-path", 's', 0, G_OPTION_ARG_FILENAME, &opt_socket_path, + "Use UNIX socket path", "PATH" }, + { "render-node", 'r', 0, G_OPTION_ARG_FILENAME, &opt_render_node, + "Specify DRM render node", "PATH" }, + { "virgl", 'v', 0, G_OPTION_ARG_NONE, &opt_virgl, + "Turn virgl rendering on", NULL }, + { NULL, } +}; + +int +main(int argc, char *argv[]) +{ + GOptionContext *context; + GError *error = NULL; + GMainLoop *loop = NULL; + int fd; + VuGpu g = { .sock_fd = -1, .drm_rnode_fd = -1 }; + + QTAILQ_INIT(&g.reslist); + QTAILQ_INIT(&g.fenceq); + + context = g_option_context_new("QEMU vhost-user-gpu"); + g_option_context_add_main_entries(context, entries, NULL); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + g_printerr("Option parsing failed: %s\n", error->message); + exit(1); + } + g_option_context_free(context); + + g.drm_rnode_fd = qemu_drm_rendernode_open(opt_render_node); + if (opt_render_node && g.drm_rnode_fd == -1) { + g_printerr("Failed to open DRM rendernode.\n"); + exit(1); + } + + if (g.drm_rnode_fd >= 0) { + if (!drm_device_init(&g.drm_dev, g.drm_rnode_fd)) { + g_warning("Failed to init DRM device, using fallback path"); + } + } + + if (opt_socket_path) { + int lsock = unix_sock_new(opt_socket_path); + fd = accept(lsock, NULL, NULL); + close(lsock); + } else { + fd = 3; + } + if (fd == -1) { + g_printerr("Invalid socket"); + exit(1); + } + + vug_init(&g.dev, fd, vg_panic, &vuiface); + + loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(loop); + g_main_loop_unref(loop); + + vg_destroy(&g); + if (g.drm_rnode_fd >= 0) { + close(g.drm_rnode_fd); + } + + return 0; +} diff --git a/contrib/vhost-user-gpu/virgl.c b/contrib/vhost-user-gpu/virgl.c new file mode 100644 index 0000000000..43413e29df --- /dev/null +++ b/contrib/vhost-user-gpu/virgl.c @@ -0,0 +1,579 @@ +/* + * Virtio vhost-user GPU Device + * + * Copyright Red Hat, Inc. 2013-2018 + * + * Authors: + * Dave Airlie + * Gerd Hoffmann + * Marc-André Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include "virgl.h" + +void +vg_virgl_update_cursor_data(VuGpu *g, uint32_t resource_id, + gpointer data) +{ + uint32_t width, height; + uint32_t *cursor; + + cursor = virgl_renderer_get_cursor_data(resource_id, &width, &height); + g_return_if_fail(cursor != NULL); + g_return_if_fail(width == 64); + g_return_if_fail(height == 64); + + memcpy(data, cursor, 64 * 64 * sizeof(uint32_t)); + free(cursor); +} + +static void +virgl_cmd_context_create(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_ctx_create cc; + + VUGPU_FILL_CMD(cc); + + virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, + cc.debug_name); +} + +static void +virgl_cmd_context_destroy(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_ctx_destroy cd; + + VUGPU_FILL_CMD(cd); + + virgl_renderer_context_destroy(cd.hdr.ctx_id); +} + +static void +virgl_cmd_create_resource_2d(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_create_2d c2d; + struct virgl_renderer_resource_create_args args; + + VUGPU_FILL_CMD(c2d); + + args.handle = c2d.resource_id; + args.target = 2; + args.format = c2d.format; + args.bind = (1 << 1); + args.width = c2d.width; + args.height = c2d.height; + args.depth = 1; + args.array_size = 1; + args.last_level = 0; + args.nr_samples = 0; + args.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP; + virgl_renderer_resource_create(&args, NULL, 0); +} + +static void +virgl_cmd_create_resource_3d(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_create_3d c3d; + struct virgl_renderer_resource_create_args args; + + VUGPU_FILL_CMD(c3d); + + args.handle = c3d.resource_id; + args.target = c3d.target; + args.format = c3d.format; + args.bind = c3d.bind; + args.width = c3d.width; + args.height = c3d.height; + args.depth = c3d.depth; + args.array_size = c3d.array_size; + args.last_level = c3d.last_level; + args.nr_samples = c3d.nr_samples; + args.flags = c3d.flags; + virgl_renderer_resource_create(&args, NULL, 0); +} + +static void +virgl_cmd_resource_unref(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_unref unref; + + VUGPU_FILL_CMD(unref); + + virgl_renderer_resource_unref(unref.resource_id); +} + +/* Not yet(?) defined in standard-headers, remove when possible */ +#ifndef VIRTIO_GPU_CAPSET_VIRGL2 +#define VIRTIO_GPU_CAPSET_VIRGL2 2 +#endif + +static void +virgl_cmd_get_capset_info(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_get_capset_info info; + struct virtio_gpu_resp_capset_info resp; + + VUGPU_FILL_CMD(info); + + if (info.capset_index == 0) { + resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL; + virgl_renderer_get_cap_set(resp.capset_id, + &resp.capset_max_version, + &resp.capset_max_size); + } else if (info.capset_index == 1) { + resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL2; + virgl_renderer_get_cap_set(resp.capset_id, + &resp.capset_max_version, + &resp.capset_max_size); + } else { + resp.capset_max_version = 0; + resp.capset_max_size = 0; + } + resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO; + vg_ctrl_response(g, cmd, &resp.hdr, sizeof(resp)); +} + +uint32_t +vg_virgl_get_num_capsets(void) +{ + uint32_t capset2_max_ver, capset2_max_size; + virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2, + &capset2_max_ver, + &capset2_max_size); + + return capset2_max_ver ? 2 : 1; +} + +static void +virgl_cmd_get_capset(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_get_capset gc; + struct virtio_gpu_resp_capset *resp; + uint32_t max_ver, max_size; + + VUGPU_FILL_CMD(gc); + + virgl_renderer_get_cap_set(gc.capset_id, &max_ver, + &max_size); + resp = g_malloc0(sizeof(*resp) + max_size); + + resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET; + virgl_renderer_fill_caps(gc.capset_id, + gc.capset_version, + (void *)resp->capset_data); + vg_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + max_size); + g_free(resp); +} + +static void +virgl_cmd_submit_3d(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_cmd_submit cs; + void *buf; + size_t s; + + VUGPU_FILL_CMD(cs); + + buf = g_malloc(cs.size); + s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, + sizeof(cs), buf, cs.size); + if (s != cs.size) { + g_critical("%s: size mismatch (%zd/%d)", __func__, s, cs.size); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + goto out; + } + + virgl_renderer_submit_cmd(buf, cs.hdr.ctx_id, cs.size / 4); + +out: + g_free(buf); +} + +static void +virgl_cmd_transfer_to_host_2d(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_transfer_to_host_2d t2d; + struct virtio_gpu_box box; + + VUGPU_FILL_CMD(t2d); + + box.x = t2d.r.x; + box.y = t2d.r.y; + box.z = 0; + box.w = t2d.r.width; + box.h = t2d.r.height; + box.d = 1; + + virgl_renderer_transfer_write_iov(t2d.resource_id, + 0, + 0, + 0, + 0, + (struct virgl_box *)&box, + t2d.offset, NULL, 0); +} + +static void +virgl_cmd_transfer_to_host_3d(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_transfer_host_3d t3d; + + VUGPU_FILL_CMD(t3d); + + virgl_renderer_transfer_write_iov(t3d.resource_id, + t3d.hdr.ctx_id, + t3d.level, + t3d.stride, + t3d.layer_stride, + (struct virgl_box *)&t3d.box, + t3d.offset, NULL, 0); +} + +static void +virgl_cmd_transfer_from_host_3d(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_transfer_host_3d tf3d; + + VUGPU_FILL_CMD(tf3d); + + virgl_renderer_transfer_read_iov(tf3d.resource_id, + tf3d.hdr.ctx_id, + tf3d.level, + tf3d.stride, + tf3d.layer_stride, + (struct virgl_box *)&tf3d.box, + tf3d.offset, NULL, 0); +} + +static void +virgl_resource_attach_backing(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_attach_backing att_rb; + struct iovec *res_iovs; + int ret; + + VUGPU_FILL_CMD(att_rb); + + ret = vg_create_mapping_iov(g, &att_rb, cmd, &res_iovs); + if (ret != 0) { + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + return; + } + + virgl_renderer_resource_attach_iov(att_rb.resource_id, + res_iovs, att_rb.nr_entries); +} + +static void +virgl_resource_detach_backing(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_detach_backing detach_rb; + struct iovec *res_iovs = NULL; + int num_iovs = 0; + + VUGPU_FILL_CMD(detach_rb); + + virgl_renderer_resource_detach_iov(detach_rb.resource_id, + &res_iovs, + &num_iovs); + if (res_iovs == NULL || num_iovs == 0) { + return; + } + g_free(res_iovs); +} + +static void +virgl_cmd_set_scanout(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_set_scanout ss; + struct virgl_renderer_resource_info info; + int ret; + + VUGPU_FILL_CMD(ss); + + if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUTS) { + g_critical("%s: illegal scanout id specified %d", + __func__, ss.scanout_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + + memset(&info, 0, sizeof(info)); + + if (ss.resource_id && ss.r.width && ss.r.height) { + ret = virgl_renderer_resource_get_info(ss.resource_id, &info); + if (ret == -1) { + g_critical("%s: illegal resource specified %d\n", + __func__, ss.resource_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + int fd = -1; + if (virgl_renderer_get_fd_for_texture(info.tex_id, &fd) < 0) { + g_critical("%s: failed to get fd for texture\n", __func__); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + assert(fd >= 0); + VhostUserGpuMsg msg = { + .request = VHOST_USER_GPU_DMABUF_SCANOUT, + .size = sizeof(VhostUserGpuDMABUFScanout), + .payload.dmabuf_scanout.scanout_id = ss.scanout_id, + .payload.dmabuf_scanout.x = ss.r.x, + .payload.dmabuf_scanout.y = ss.r.y, + .payload.dmabuf_scanout.width = ss.r.width, + .payload.dmabuf_scanout.height = ss.r.height, + .payload.dmabuf_scanout.fd_width = info.width, + .payload.dmabuf_scanout.fd_height = info.height, + .payload.dmabuf_scanout.fd_stride = info.stride, + .payload.dmabuf_scanout.fd_flags = info.flags, + .payload.dmabuf_scanout.fd_drm_fourcc = info.drm_fourcc + }; + vg_send_msg(g, &msg, fd); + close(fd); + } else { + VhostUserGpuMsg msg = { + .request = VHOST_USER_GPU_DMABUF_SCANOUT, + .size = sizeof(VhostUserGpuDMABUFScanout), + .payload.dmabuf_scanout.scanout_id = ss.scanout_id, + }; + g_debug("disable scanout"); + vg_send_msg(g, &msg, -1); + } + g->scanout[ss.scanout_id].resource_id = ss.resource_id; +} + +static void +virgl_cmd_resource_flush(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_resource_flush rf; + int i; + + VUGPU_FILL_CMD(rf); + + if (!rf.resource_id) { + g_debug("bad resource id for flush..?"); + return; + } + for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) { + if (g->scanout[i].resource_id != rf.resource_id) { + continue; + } + VhostUserGpuMsg msg = { + .request = VHOST_USER_GPU_DMABUF_UPDATE, + .size = sizeof(VhostUserGpuUpdate), + .payload.update.scanout_id = i, + .payload.update.x = rf.r.x, + .payload.update.y = rf.r.y, + .payload.update.width = rf.r.width, + .payload.update.height = rf.r.height + }; + vg_send_msg(g, &msg, -1); + vg_wait_ok(g); + } +} + +static void +virgl_cmd_ctx_attach_resource(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_ctx_resource att_res; + + VUGPU_FILL_CMD(att_res); + + virgl_renderer_ctx_attach_resource(att_res.hdr.ctx_id, att_res.resource_id); +} + +static void +virgl_cmd_ctx_detach_resource(VuGpu *g, + struct virtio_gpu_ctrl_command *cmd) +{ + struct virtio_gpu_ctx_resource det_res; + + VUGPU_FILL_CMD(det_res); + + virgl_renderer_ctx_detach_resource(det_res.hdr.ctx_id, det_res.resource_id); +} + +void vg_virgl_process_cmd(VuGpu *g, struct virtio_gpu_ctrl_command *cmd) +{ + virgl_renderer_force_ctx_0(); + switch (cmd->cmd_hdr.type) { + case VIRTIO_GPU_CMD_CTX_CREATE: + virgl_cmd_context_create(g, cmd); + break; + case VIRTIO_GPU_CMD_CTX_DESTROY: + virgl_cmd_context_destroy(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: + virgl_cmd_create_resource_2d(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D: + virgl_cmd_create_resource_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_SUBMIT_3D: + virgl_cmd_submit_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: + virgl_cmd_transfer_to_host_2d(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D: + virgl_cmd_transfer_to_host_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D: + virgl_cmd_transfer_from_host_3d(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING: + virgl_resource_attach_backing(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING: + virgl_resource_detach_backing(g, cmd); + break; + case VIRTIO_GPU_CMD_SET_SCANOUT: + virgl_cmd_set_scanout(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_FLUSH: + virgl_cmd_resource_flush(g, cmd); + break; + case VIRTIO_GPU_CMD_RESOURCE_UNREF: + virgl_cmd_resource_unref(g, cmd); + break; + case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE: + /* TODO add security */ + virgl_cmd_ctx_attach_resource(g, cmd); + break; + case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE: + /* TODO add security */ + virgl_cmd_ctx_detach_resource(g, cmd); + break; + case VIRTIO_GPU_CMD_GET_CAPSET_INFO: + virgl_cmd_get_capset_info(g, cmd); + break; + case VIRTIO_GPU_CMD_GET_CAPSET: + virgl_cmd_get_capset(g, cmd); + break; + case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: + vg_get_display_info(g, cmd); + break; + default: + g_debug("TODO handle ctrl %x\n", cmd->cmd_hdr.type); + cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; + break; + } + + if (cmd->finished) { + return; + } + + if (cmd->error) { + g_warning("%s: ctrl 0x%x, error 0x%x\n", __func__, + cmd->cmd_hdr.type, cmd->error); + vg_ctrl_response_nodata(g, cmd, cmd->error); + return; + } + + if (!(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) { + vg_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA); + return; + } + + g_debug("Creating fence id:%" PRId64 " type:%d", + cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type); + virgl_renderer_create_fence(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type); +} + +static void +virgl_write_fence(void *opaque, uint32_t fence) +{ + VuGpu *g = opaque; + struct virtio_gpu_ctrl_command *cmd, *tmp; + + QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) { + /* + * the guest can end up emitting fences out of order + * so we should check all fenced cmds not just the first one. + */ + if (cmd->cmd_hdr.fence_id > fence) { + continue; + } + g_debug("FENCE %" PRIu64, cmd->cmd_hdr.fence_id); + vg_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA); + QTAILQ_REMOVE(&g->fenceq, cmd, next); + g_free(cmd); + g->inflight--; + } +} + +#if defined(VIRGL_RENDERER_CALLBACKS_VERSION) && \ + VIRGL_RENDERER_CALLBACKS_VERSION >= 2 +static int +virgl_get_drm_fd(void *opaque) +{ + VuGpu *g = opaque; + + return g->drm_rnode_fd; +} +#endif + +static struct virgl_renderer_callbacks virgl_cbs = { +#if defined(VIRGL_RENDERER_CALLBACKS_VERSION) && \ + VIRGL_RENDERER_CALLBACKS_VERSION >= 2 + .get_drm_fd = virgl_get_drm_fd, + .version = 2, +#else + .version = 1, +#endif + .write_fence = virgl_write_fence, +}; + +static void +vg_virgl_poll(VuDev *dev, int condition, void *data) +{ + virgl_renderer_poll(); +} + +bool +vg_virgl_init(VuGpu *g) +{ + int ret; + + if (g->drm_rnode_fd && virgl_cbs.version == 1) { + g_warning("virgl will use the default rendernode"); + } + + ret = virgl_renderer_init(g, + VIRGL_RENDERER_USE_EGL | + VIRGL_RENDERER_THREAD_SYNC, + &virgl_cbs); + if (ret != 0) { + return false; + } + + ret = virgl_renderer_get_poll_fd(); + if (ret != -1) { + g->renderer_source = + vug_source_new(&g->dev, ret, G_IO_IN, vg_virgl_poll, g); + } + + return true; +} diff --git a/MAINTAINERS b/MAINTAINERS index 42a5d46acd..5dc312f7de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1344,6 +1344,8 @@ M: Marc-André Lureau M: Gerd Hoffmann S: Maintained F: docs/interop/vhost-user-gpu.txt +F: contrib/vhost-user-gpu +F: hw/display/vhost-user-* Cirrus VGA M: Gerd Hoffmann diff --git a/Makefile b/Makefile index 1d4d9441b1..5c42e8897e 100644 --- a/Makefile +++ b/Makefile @@ -422,6 +422,7 @@ dummy := $(call unnest-vars,, \ vhost-user-scsi-obj-y \ vhost-user-blk-obj-y \ vhost-user-input-obj-y \ + vhost-user-gpu-obj-y \ qga-vss-dll-obj-y \ block-obj-y \ block-obj-m \ @@ -722,6 +723,8 @@ vhost-user-blk$(EXESUF): $(vhost-user-blk-obj-y) libvhost-user.a $(call LINK, $^) vhost-user-input$(EXESUF): $(vhost-user-input-obj-y) libvhost-user.a libqemuutil.a $(call LINK, $^) +vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) libqemuutil.a libqemustub.a + $(call LINK, $^) module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak $(call quiet-command,$(PYTHON) $< $@ \ diff --git a/Makefile.objs b/Makefile.objs index b0f48d667c..a8789a165e 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -194,6 +194,7 @@ vhost-user-scsi.o-libs := $(LIBISCSI_LIBS) vhost-user-scsi-obj-y = contrib/vhost-user-scsi/ vhost-user-blk-obj-y = contrib/vhost-user-blk/ vhost-user-input-obj-y = contrib/vhost-user-input/ +vhost-user-gpu-obj-y = contrib/vhost-user-gpu/ ###################################################################### trace-events-subdirs = diff --git a/configure b/configure index 28aef55d06..cab6edd35b 100755 --- a/configure +++ b/configure @@ -3815,6 +3815,20 @@ libs_softmmu="$libs_softmmu $fdt_libs" ########################################## # opengl probe (for sdl2, gtk, milkymist-tmu2) +libdrm="no" +if $pkg_config libdrm; then + libdrm_cflags="$($pkg_config --cflags libdrm)" + libdrm_libs="$($pkg_config --libs libdrm)" + libdrm="yes" +fi + +libdrm_intel="no" +if $pkg_config libdrm_intel; then + libdrm_intel_cflags="$($pkg_config --cflags libdrm_intel)" + libdrm_intel_libs="$($pkg_config --libs libdrm_intel)" + libdrm_intel="yes" +fi + if test "$opengl" != "no" ; then opengl_pkgs="epoxy libdrm gbm" if $pkg_config $opengl_pkgs; then @@ -5554,6 +5568,9 @@ if test "$want_tools" = "yes" ; then if [ "$linux" = "yes" ] ; then tools="vhost-user-input\$(EXESUF) $tools" fi + if [ "$linux" = "yes" -a "$virglrenderer" = "yes" -a "$libdrm" = "yes" ] ; then + tools="vhost-user-gpu\$(EXESUF) $tools" + fi fi if test "$softmmu" = yes ; then if test "$linux" = yes; then @@ -6420,6 +6437,18 @@ if test "$opengl" = "yes" ; then fi fi +if test "$libdrm" = "yes" ; then + echo "CONFIG_LIBDRM=y" >> $config_host_mak + echo "LIBDRM_LIBS=$libdrm_libs" >> $config_host_mak + echo "LIBDRM_CFLAGS=$libdrm_cflags" >> $config_host_mak +fi + +if test "$libdrm_intel" = "yes" ; then + echo "CONFIG_LIBDRM_INTEL=y" >> $config_host_mak + echo "LIBDRM_INTEL_LIBS=$libdrm_intel_libs" >> $config_host_mak + echo "LIBDRM_INTEL_CFLAGS=$libdrm_intel_cflags" >> $config_host_mak +fi + if test "$malloc_trim" = "yes" ; then echo "CONFIG_MALLOC_TRIM=y" >> $config_host_mak fi @@ -7169,6 +7198,9 @@ echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak done # for target in $targets +echo "PIXMAN_CFLAGS=$pixman_cflags" >> $config_host_mak +echo "PIXMAN_LIBS=$pixman_libs" >> $config_host_mak + if [ "$fdt" = "git" ]; then echo "config-host.h: subdir-dtc" >> $config_host_mak fi diff --git a/contrib/vhost-user-gpu/Makefile.objs b/contrib/vhost-user-gpu/Makefile.objs new file mode 100644 index 0000000000..4da8c09cbb --- /dev/null +++ b/contrib/vhost-user-gpu/Makefile.objs @@ -0,0 +1,10 @@ +vhost-user-gpu-obj-y = main.o virgl.o drm.o + +main.o-cflags := $(PIXMAN_CFLAGS) +main.o-libs := $(PIXMAN_LIBS) + +virgl.o-cflags := $(VIRGL_CFLAGS) +virgl.o-libs := $(VIRGL_LIBS) + +drm.o-cflags := $(LIBDRM_CFLAGS) $(LIBDRM_INTEL_CFLAGS) +drm.o-libs := $(LIBDRM_LIBS) $(LIBDRM_INTEL_LIBS) From patchwork Mon Jun 18 16:17:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931052 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418cB40nq6z9s1R for ; Tue, 19 Jun 2018 02:34:20 +1000 (AEST) Received: from localhost ([::1]:35816 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx6f-0005lM-LS for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:34:17 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44088) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrE-0002Ek-Df for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwrD-0005G0-GU for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:20 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44996 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwrD-0005FL-Bn for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:19 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0E7B7401EF03 for ; Mon, 18 Jun 2018 16:18:19 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id B6FFD111AF16; Mon, 18 Jun 2018 16:18:18 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:23 +0200 Message-Id: <20180618161729.334-21-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:18:19 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:18:19 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 20/26] virtio-gpu: remove unused qdev X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Marc-André Lureau --- include/hw/virtio/virtio-gpu.h | 1 - hw/display/virtio-gpu.c | 1 - 2 files changed, 2 deletions(-) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index d6ba61f2f1..6cb13d2711 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -102,7 +102,6 @@ typedef struct VirtIOGPU { int enable; int config_size; - DeviceState *qdev; QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist; QTAILQ_HEAD(, virtio_gpu_ctrl_command) cmdq; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 6a55416be7..7f7e18c2ee 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1192,7 +1192,6 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) QTAILQ_INIT(&g->fenceq); g->enabled_output_bitmask = 1; - g->qdev = qdev; for (i = 0; i < g->conf.max_outputs; i++) { g->scanout[i].con = From patchwork Mon Jun 18 16:17:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931045 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418c354pCcz9s1R for ; Tue, 19 Jun 2018 02:28:17 +1000 (AEST) Received: from localhost ([::1]:35786 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx0p-00016T-8Z for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:28:15 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44124) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrF-0002GU-W3 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwrF-0005IS-0I for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:21 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44998 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwrE-0005IC-S0 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:20 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8AFF3401EF03 for ; Mon, 18 Jun 2018 16:18:20 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3B2EC111AF16; Mon, 18 Jun 2018 16:18:20 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:24 +0200 Message-Id: <20180618161729.334-22-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:18:20 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 18 Jun 2018 16:18:20 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 21/26] virtio-gpu: remove unused config_size X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Marc-André Lureau --- include/hw/virtio/virtio-gpu.h | 2 -- hw/display/virtio-gpu.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 6cb13d2711..1cf8ec1aa8 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -101,8 +101,6 @@ typedef struct VirtIOGPU { int enable; - int config_size; - QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist; QTAILQ_HEAD(, virtio_gpu_ctrl_command) cmdq; QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 7f7e18c2ee..cd48a928ca 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1162,10 +1162,9 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) } } - g->config_size = sizeof(struct virtio_gpu_config); g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, - g->config_size); + sizeof(struct virtio_gpu_config)); g->req_state[0].width = g->conf.xres; g->req_state[0].height = g->conf.yres; From patchwork Mon Jun 18 16:17:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931048 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418c6H4jVpz9s1R for ; Tue, 19 Jun 2018 02:31:03 +1000 (AEST) Received: from localhost ([::1]:35802 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx3V-0003Ro-9h for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:31:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44141) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrH-0002Gc-J9 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwrG-0005KE-FG for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:23 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45482 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwrG-0005JP-9c for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:22 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EDDC07DAC3 for ; Mon, 18 Jun 2018 16:18:21 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id A287D2026D5B; Mon, 18 Jun 2018 16:18:21 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:25 +0200 Message-Id: <20180618161729.334-23-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:21 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:21 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 22/26] virtio-gpu: block both 2d and 3d rendering X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Now that 2d commands are translated to 3d rendering, qemu must stop sending 3d updates (from 2d) to Spice as well. Signed-off-by: Marc-André Lureau --- include/hw/virtio/virtio-gpu.h | 1 - hw/display/virtio-gpu-3d.c | 21 --------------------- hw/display/virtio-gpu.c | 25 ++++++++++++++++++++++--- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 1cf8ec1aa8..fb74fba4a9 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -171,7 +171,6 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd); void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); -void virtio_gpu_gl_block(void *opaque, bool block); int virtio_gpu_virgl_init(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); #endif diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c index 3558f38fe8..6fee0e8582 100644 --- a/hw/display/virtio-gpu-3d.c +++ b/hw/display/virtio-gpu-3d.c @@ -404,11 +404,6 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, { VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); - cmd->waiting = g->renderer_blocked; - if (cmd->waiting) { - return; - } - virgl_renderer_force_ctx_0(); switch (cmd->cmd_hdr.type) { case VIRTIO_GPU_CMD_CTX_CREATE: @@ -604,22 +599,6 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g) } } -void virtio_gpu_gl_block(void *opaque, bool block) -{ - VirtIOGPU *g = opaque; - - if (block) { - g->renderer_blocked++; - } else { - g->renderer_blocked--; - } - assert(g->renderer_blocked >= 0); - - if (g->renderer_blocked == 0) { - virtio_gpu_process_cmdq(g); - } -} - int virtio_gpu_virgl_init(VirtIOGPU *g) { int ret; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index cd48a928ca..48b3e0ceaa 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -813,12 +813,15 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) while (!QTAILQ_EMPTY(&g->cmdq)) { cmd = QTAILQ_FIRST(&g->cmdq); - /* process command */ - VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd, - g, cmd); + cmd->waiting = g->renderer_blocked; if (cmd->waiting) { break; } + + /* process command */ + VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd, + g, cmd); + QTAILQ_REMOVE(&g->cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->conf)) { g->stats.requests++; @@ -954,6 +957,22 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) return 0; } +static void virtio_gpu_gl_block(void *opaque, bool block) +{ + VirtIOGPU *g = opaque; + + if (block) { + g->renderer_blocked++; + } else { + g->renderer_blocked--; + } + assert(g->renderer_blocked >= 0); + + if (g->renderer_blocked == 0) { + virtio_gpu_process_cmdq(g); + } +} + const GraphicHwOps virtio_gpu_ops = { .invalidate = virtio_gpu_invalidate_display, .gfx_update = virtio_gpu_update_display, From patchwork Mon Jun 18 16:17:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931053 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418cDn1v5cz9s2t for ; Tue, 19 Jun 2018 02:36:41 +1000 (AEST) Received: from localhost ([::1]:35853 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUx8w-0007dE-RS for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:36:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44157) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrI-0002Ge-Qa for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwrH-0005Ll-Te for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:24 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:60992 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwrH-0005L3-PP for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:23 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 64421401DE60 for ; Mon, 18 Jun 2018 16:18:23 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 183CA2026D5B; Mon, 18 Jun 2018 16:18:22 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:26 +0200 Message-Id: <20180618161729.334-24-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 18 Jun 2018 16:18:23 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 18 Jun 2018 16:18:23 +0000 (UTC) for IP:'10.11.54.4' DOMAIN:'int-mx04.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 23/26] virtio-gpu: remove useless 'waiting' field X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Let's check renderer_blocked instead directly. Signed-off-by: Marc-André Lureau --- include/hw/virtio/virtio-gpu.h | 1 - hw/display/virtio-gpu.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index fb74fba4a9..5b19b0d9d4 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -86,7 +86,6 @@ struct virtio_gpu_ctrl_command { VirtQueue *vq; struct virtio_gpu_ctrl_hdr cmd_hdr; uint32_t error; - bool waiting; bool finished; QTAILQ_ENTRY(virtio_gpu_ctrl_command) next; }; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 48b3e0ceaa..37055926d3 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -813,8 +813,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) while (!QTAILQ_EMPTY(&g->cmdq)) { cmd = QTAILQ_FIRST(&g->cmdq); - cmd->waiting = g->renderer_blocked; - if (cmd->waiting) { + if (g->renderer_blocked) { break; } @@ -863,7 +862,6 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) cmd->vq = vq; cmd->error = 0; cmd->finished = false; - cmd->waiting = false; QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next); cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); } From patchwork Mon Jun 18 16:17:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931056 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418cLl2Qs3z9s2t for ; Tue, 19 Jun 2018 02:41:51 +1000 (AEST) Received: from localhost ([::1]:35896 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUxDx-0002fe-29 for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:41:49 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44187) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrN-0002KM-KI for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwrJ-0005NU-RK for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:29 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57730 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwrJ-0005Mp-Ji for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:25 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 43EAC402178A for ; Mon, 18 Jun 2018 16:18:25 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 81D19200AC23; Mon, 18 Jun 2018 16:18:24 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:27 +0200 Message-Id: <20180618161729.334-25-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 18 Jun 2018 16:18:25 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 18 Jun 2018 16:18:25 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 24/26] virtio-gpu: split virtio-gpu, introduce virtio-gpu-base X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add a base class that is common to virtio-gpu and vhost-user-gpu devices. Signed-off-by: Marc-André Lureau --- include/hw/virtio/virtio-gpu.h | 72 +++++-- hw/display/virtio-gpu-3d.c | 49 ++--- hw/display/virtio-gpu-base.c | 292 +++++++++++++++++++++++++++++ hw/display/virtio-gpu-pci.c | 2 +- hw/display/virtio-gpu.c | 331 ++++++--------------------------- hw/display/virtio-vga.c | 15 +- hw/display/Makefile.objs | 2 +- 7 files changed, 446 insertions(+), 317 deletions(-) create mode 100644 hw/display/virtio-gpu-base.c diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 5b19b0d9d4..4a17000ce4 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -27,6 +27,14 @@ #define VIRTIO_GPU_CAPSET_VIRGL2 2 #endif +#define TYPE_VIRTIO_GPU_BASE "virtio-gpu-base" +#define VIRTIO_GPU_BASE(obj) \ + OBJECT_CHECK(VirtIOGPUBase, (obj), TYPE_VIRTIO_GPU_BASE) +#define VIRTIO_GPU_BASE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtIOGPUBaseClass, obj, TYPE_VIRTIO_GPU_BASE) +#define VIRTIO_GPU_BASE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtIOGPUBaseClass, klass, TYPE_VIRTIO_GPU_BASE) + #define TYPE_VIRTIO_GPU "virtio-gpu-device" #define VIRTIO_GPU(obj) \ OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU) @@ -63,7 +71,7 @@ struct virtio_gpu_requested_state { int x, y; }; -enum virtio_gpu_conf_flags { +enum virtio_gpu_base_conf_flags { VIRTIO_GPU_FLAG_VIRGL_ENABLED = 1, VIRTIO_GPU_FLAG_STATS_ENABLED, }; @@ -73,8 +81,7 @@ enum virtio_gpu_conf_flags { #define virtio_gpu_stats_enabled(_cfg) \ (_cfg.flags & (1 << VIRTIO_GPU_FLAG_STATS_ENABLED)) -struct virtio_gpu_conf { - uint64_t max_hostmem; +struct virtio_gpu_base_conf { uint32_t max_outputs; uint32_t flags; uint32_t xres; @@ -90,31 +97,53 @@ struct virtio_gpu_ctrl_command { QTAILQ_ENTRY(virtio_gpu_ctrl_command) next; }; -typedef struct VirtIOGPU { +typedef struct VirtIOGPUBase { VirtIODevice parent_obj; - QEMUBH *ctrl_bh; - QEMUBH *cursor_bh; + Error *migration_blocker; + + struct virtio_gpu_base_conf conf; + struct virtio_gpu_config virtio_config; + + bool use_virgl_renderer; + int renderer_blocked; + int enable; + + struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS]; + + int enabled_output_bitmask; + struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUTS]; +} VirtIOGPUBase; + +typedef struct VirtIOGPUBaseClass { + VirtioDeviceClass parent; + + void (*gl_unblock)(VirtIOGPUBase *g); +} VirtIOGPUBaseClass; + +#define VIRTIO_GPU_BASE_PROPERTIES(_state, _conf) \ + DEFINE_PROP_UINT32("max_outputs", _state, _conf.max_outputs, 1), \ + DEFINE_PROP_UINT32("xres", _state, _conf.xres, 1024), \ + DEFINE_PROP_UINT32("yres", _state, _conf.yres, 768) + +typedef struct VirtIOGPU { + VirtIOGPUBase parent_obj; + + uint64_t conf_max_hostmem; + VirtQueue *ctrl_vq; VirtQueue *cursor_vq; - int enable; + QEMUBH *ctrl_bh; + QEMUBH *cursor_bh; QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist; QTAILQ_HEAD(, virtio_gpu_ctrl_command) cmdq; QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq; - struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS]; - struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUTS]; - - struct virtio_gpu_conf conf; uint64_t hostmem; - int enabled_output_bitmask; - struct virtio_gpu_config virtio_config; - bool use_virgl_renderer; bool renderer_inited; - int renderer_blocked; QEMUTimer *fence_poll; QEMUTimer *print_stats; @@ -125,8 +154,6 @@ typedef struct VirtIOGPU { uint32_t req_3d; uint32_t bytes_3d; } stats; - - Error *migration_blocker; } VirtIOGPU; extern const GraphicHwOps virtio_gpu_ops; @@ -149,6 +176,16 @@ extern const GraphicHwOps virtio_gpu_ops; } \ } while (0) +/* virtio-gpu-base.c */ +bool virtio_gpu_base_device_realize(DeviceState *qdev, + int num_capsets, + VirtIOHandleOutput ctrl_cb, + VirtIOHandleOutput cursor_cb, + Error **errp); +void virtio_gpu_base_reset(VirtIOGPUBase *g); +void virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, + struct virtio_gpu_resp_display_info *dpy_info); + /* virtio-gpu.c */ void virtio_gpu_ctrl_response(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd, @@ -172,4 +209,5 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g); void virtio_gpu_virgl_reset(VirtIOGPU *g); int virtio_gpu_virgl_init(VirtIOGPU *g); int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g); + #endif diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c index 6fee0e8582..173c9d21e5 100644 --- a/hw/display/virtio-gpu-3d.c +++ b/hw/display/virtio-gpu-3d.c @@ -118,11 +118,11 @@ static void virgl_cmd_context_destroy(VirtIOGPU *g, static void virtio_gpu_rect_update(VirtIOGPU *g, int idx, int x, int y, int width, int height) { - if (!g->scanout[idx].con) { + if (!g->parent_obj.scanout[idx].con) { return; } - dpy_gl_update(g->scanout[idx].con, x, y, width, height); + dpy_gl_update(g->parent_obj.scanout[idx].con, x, y, width, height); } static void virgl_cmd_resource_flush(VirtIOGPU *g, @@ -135,8 +135,8 @@ static void virgl_cmd_resource_flush(VirtIOGPU *g, trace_virtio_gpu_cmd_res_flush(rf.resource_id, rf.r.width, rf.r.height, rf.r.x, rf.r.y); - for (i = 0; i < g->conf.max_outputs; i++) { - if (g->scanout[i].resource_id != rf.resource_id) { + for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { + if (g->parent_obj.scanout[i].resource_id != rf.resource_id) { continue; } virtio_gpu_rect_update(g, i, rf.r.x, rf.r.y, rf.r.width, rf.r.height); @@ -154,13 +154,13 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g, trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, ss.r.width, ss.r.height, ss.r.x, ss.r.y); - if (ss.scanout_id >= g->conf.max_outputs) { + if (ss.scanout_id >= g->parent_obj.conf.max_outputs) { qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", __func__, ss.scanout_id); cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; return; } - g->enable = 1; + g->parent_obj.enable = 1; memset(&info, 0, sizeof(info)); @@ -173,20 +173,22 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g, cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; return; } - qemu_console_resize(g->scanout[ss.scanout_id].con, + qemu_console_resize(g->parent_obj.scanout[ss.scanout_id].con, ss.r.width, ss.r.height); virgl_renderer_force_ctx_0(); - dpy_gl_scanout_texture(g->scanout[ss.scanout_id].con, info.tex_id, - info.flags & 1 /* FIXME: Y_0_TOP */, - info.width, info.height, - ss.r.x, ss.r.y, ss.r.width, ss.r.height); + dpy_gl_scanout_texture( + g->parent_obj.scanout[ss.scanout_id].con, info.tex_id, + info.flags & 1 /* FIXME: Y_0_TOP */, + info.width, info.height, + ss.r.x, ss.r.y, ss.r.width, ss.r.height); } else { if (ss.scanout_id != 0) { - dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL); + dpy_gfx_replace_surface( + g->parent_obj.scanout[ss.scanout_id].con, NULL); } - dpy_gl_scanout_disable(g->scanout[ss.scanout_id].con); + dpy_gl_scanout_disable(g->parent_obj.scanout[ss.scanout_id].con); } - g->scanout[ss.scanout_id].resource_id = ss.resource_id; + g->parent_obj.scanout[ss.scanout_id].resource_id = ss.resource_id; } static void virgl_cmd_submit_3d(VirtIOGPU *g, @@ -209,7 +211,7 @@ static void virgl_cmd_submit_3d(VirtIOGPU *g, goto out; } - if (virtio_gpu_stats_enabled(g->conf)) { + if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.req_3d++; g->stats.bytes_3d += cs.size; } @@ -504,7 +506,7 @@ static void virgl_write_fence(void *opaque, uint32_t fence) QTAILQ_REMOVE(&g->fenceq, cmd, next); g_free(cmd); g->inflight--; - if (virtio_gpu_stats_enabled(g->conf)) { + if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { fprintf(stderr, "inflight: %3d (-)\r", g->inflight); } } @@ -521,7 +523,7 @@ virgl_create_context(void *opaque, int scanout_idx, qparams.major_ver = params->major_ver; qparams.minor_ver = params->minor_ver; - ctx = dpy_gl_ctx_create(g->scanout[scanout_idx].con, &qparams); + ctx = dpy_gl_ctx_create(g->parent_obj.scanout[scanout_idx].con, &qparams); return (virgl_renderer_gl_context)ctx; } @@ -530,7 +532,7 @@ static void virgl_destroy_context(void *opaque, virgl_renderer_gl_context ctx) VirtIOGPU *g = opaque; QEMUGLContext qctx = (QEMUGLContext)ctx; - dpy_gl_ctx_destroy(g->scanout[0].con, qctx); + dpy_gl_ctx_destroy(g->parent_obj.scanout[0].con, qctx); } static int virgl_make_context_current(void *opaque, int scanout_idx, @@ -539,7 +541,8 @@ static int virgl_make_context_current(void *opaque, int scanout_idx, VirtIOGPU *g = opaque; QEMUGLContext qctx = (QEMUGLContext)ctx; - return dpy_gl_ctx_make_current(g->scanout[scanout_idx].con, qctx); + return dpy_gl_ctx_make_current(g->parent_obj.scanout[scanout_idx].con, + qctx); } static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = { @@ -591,11 +594,11 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g) int i; /* virgl_renderer_reset() ??? */ - for (i = 0; i < g->conf.max_outputs; i++) { + for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { if (i != 0) { - dpy_gfx_replace_surface(g->scanout[i].con, NULL); + dpy_gfx_replace_surface(g->parent_obj.scanout[i].con, NULL); } - dpy_gl_scanout_disable(g->scanout[i].con); + dpy_gl_scanout_disable(g->parent_obj.scanout[i].con); } } @@ -611,7 +614,7 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL, virtio_gpu_fence_poll, g); - if (virtio_gpu_stats_enabled(g->conf)) { + if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL, virtio_gpu_print_stats, g); timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c new file mode 100644 index 0000000000..2619e94304 --- /dev/null +++ b/hw/display/virtio-gpu-base.c @@ -0,0 +1,292 @@ +/* + * Virtio GPU Device + * + * Copyright Red Hat, Inc. 2013-2014 + * + * Authors: + * Dave Airlie + * Gerd Hoffmann + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "hw/virtio/virtio-gpu.h" +#include "migration/blocker.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "trace.h" + +void +virtio_gpu_base_reset(VirtIOGPUBase *g) +{ + int i; + + g->enable = 0; + g->use_virgl_renderer = false; + + for (i = 0; i < g->conf.max_outputs; i++) { + g->scanout[i].resource_id = 0; + g->scanout[i].width = 0; + g->scanout[i].height = 0; + g->scanout[i].x = 0; + g->scanout[i].y = 0; + g->scanout[i].ds = NULL; + } +} + +void +virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, + struct virtio_gpu_resp_display_info *dpy_info) +{ + int i; + + for (i = 0; i < g->conf.max_outputs; i++) { + if (g->enabled_output_bitmask & (1 << i)) { + dpy_info->pmodes[i].enabled = 1; + dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width); + dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height); + } + } +} + +static void virtio_gpu_invalidate_display(void *opaque) +{ +} + +static void virtio_gpu_update_display(void *opaque) +{ +} + +static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata) +{ +} + +static void virtio_gpu_notify_event(VirtIOGPUBase *g, uint32_t event_type) +{ + g->virtio_config.events_read |= event_type; + virtio_notify_config(&g->parent_obj); +} + +static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) +{ + VirtIOGPUBase *g = opaque; + + if (idx >= g->conf.max_outputs) { + return -1; + } + + g->req_state[idx].x = info->xoff; + g->req_state[idx].y = info->yoff; + g->req_state[idx].width = info->width; + g->req_state[idx].height = info->height; + + if (info->width && info->height) { + g->enabled_output_bitmask |= (1 << idx); + } else { + g->enabled_output_bitmask &= ~(1 << idx); + } + + /* send event to guest */ + virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY); + return 0; +} + +static void +virtio_gpu_gl_block(void *opaque, bool block) +{ + VirtIOGPUBase *g = opaque; + VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_GET_CLASS(g); + + if (block) { + g->renderer_blocked++; + } else { + g->renderer_blocked--; + } + assert(g->renderer_blocked >= 0); + if (g->renderer_blocked == 0) { + vgc->gl_unblock(g); + } +} + +const GraphicHwOps virtio_gpu_ops = { + .invalidate = virtio_gpu_invalidate_display, + .gfx_update = virtio_gpu_update_display, + .text_update = virtio_gpu_text_update, + .ui_info = virtio_gpu_ui_info, + .gl_block = virtio_gpu_gl_block, +}; + +bool +virtio_gpu_base_device_realize(DeviceState *qdev, + int num_capsets, + VirtIOHandleOutput ctrl_cb, + VirtIOHandleOutput cursor_cb, + Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(qdev); + VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); + Error *local_err = NULL; + int i; + + if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { + error_setg(errp, "virtio-gpu does not support vIOMMU yet"); + return false; + } + + if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { + error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS); + return false; + } + + g->use_virgl_renderer = false; + if (virtio_gpu_virgl_enabled(g->conf)) { + error_setg(&g->migration_blocker, "virgl is not yet migratable"); + migrate_add_blocker(g->migration_blocker, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_free(g->migration_blocker); + return false; + } + } + + g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); + virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, + sizeof(struct virtio_gpu_config)); + + if (virtio_gpu_virgl_enabled(g->conf)) { + /* use larger control queue in 3d mode */ + virtio_add_queue(vdev, 256, ctrl_cb); + virtio_add_queue(vdev, 16, cursor_cb); + g->virtio_config.num_capsets = num_capsets; + } else { + virtio_add_queue(vdev, 64, ctrl_cb); + virtio_add_queue(vdev, 16, cursor_cb); + } + + g->enabled_output_bitmask = 1; + + g->req_state[0].width = g->conf.xres; + g->req_state[0].height = g->conf.yres; + + for (i = 0; i < g->conf.max_outputs; i++) { + g->scanout[i].con = + graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); + if (i > 0) { + dpy_gfx_replace_surface(g->scanout[i].con, NULL); + } + } + + return true; +} + +static void +virtio_gpu_base_get_config(VirtIODevice *vdev, uint8_t *config) +{ + VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); + memcpy(config, &g->virtio_config, sizeof(g->virtio_config)); +} + +static void +virtio_gpu_base_set_config(VirtIODevice *vdev, const uint8_t *config) +{ + VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); + struct virtio_gpu_config vgconfig; + + memcpy(&vgconfig, config, sizeof(g->virtio_config)); + + if (vgconfig.events_clear) { + g->virtio_config.events_read &= ~vgconfig.events_clear; + } +} + +static uint64_t +virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) +{ + VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); + + if (virtio_gpu_virgl_enabled(g->conf)) { + features |= (1 << VIRTIO_GPU_F_VIRGL); + } + return features; +} + +static void +virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features) +{ + static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); + VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); + + g->use_virgl_renderer = ((features & virgl) == virgl); + trace_virtio_gpu_features(g->use_virgl_renderer); +} + +static void +virtio_gpu_base_device_unrealize(DeviceState *qdev, Error **errp) +{ + VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev); + + if (g->migration_blocker) { + migrate_del_blocker(g->migration_blocker); + error_free(g->migration_blocker); + } +} + +static void +virtio_gpu_base_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + vdc->unrealize = virtio_gpu_base_device_unrealize; + vdc->get_features = virtio_gpu_base_get_features; + vdc->set_features = virtio_gpu_base_set_features; + vdc->get_config = virtio_gpu_base_get_config; + vdc->set_config = virtio_gpu_base_set_config; + + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + dc->hotpluggable = false; +} + +static const TypeInfo virtio_gpu_base_info = { + .name = TYPE_VIRTIO_GPU_BASE, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOGPUBase), + .class_size = sizeof(VirtIOGPUBaseClass), + .class_init = virtio_gpu_base_class_init, + .abstract = true +}; + +static void +virtio_register_types(void) +{ + type_register_static(&virtio_gpu_base_info); +} + +type_init(virtio_register_types) + +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408); + +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24); diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index cece4aa495..741badd909 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -27,7 +27,7 @@ static Property virtio_gpu_pci_properties[] = { static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev); - VirtIOGPU *g = &vgpu->vdev; + VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vgpu->vdev); DeviceState *vdev = DEVICE(&vgpu->vdev); int i; Error *local_error = NULL; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 37055926d3..f4f67347e4 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -20,9 +20,9 @@ #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-gpu-bswap.h" #include "hw/virtio/virtio-bus.h" -#include "migration/blocker.h" #include "qemu/log.h" #include "qapi/error.h" +#include "qemu/error-report.h" #define VIRTIO_GPU_VM_VERSION 1 @@ -35,7 +35,7 @@ static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res); #include #define VIRGL(_g, _virgl, _simple, ...) \ do { \ - if (_g->use_virgl_renderer) { \ + if (_g->parent_obj.use_virgl_renderer) { \ _virgl(__VA_ARGS__); \ } else { \ _simple(__VA_ARGS__); \ @@ -103,10 +103,10 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) struct virtio_gpu_scanout *s; bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR; - if (cursor->pos.scanout_id >= g->conf.max_outputs) { + if (cursor->pos.scanout_id >= g->parent_obj.conf.max_outputs) { return; } - s = &g->scanout[cursor->pos.scanout_id]; + s = &g->parent_obj.scanout[cursor->pos.scanout_id]; trace_virtio_gpu_update_cursor(cursor->pos.scanout_id, cursor->pos.x, @@ -137,50 +137,6 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) cursor->resource_id ? 1 : 0); } -static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config) -{ - VirtIOGPU *g = VIRTIO_GPU(vdev); - memcpy(config, &g->virtio_config, sizeof(g->virtio_config)); -} - -static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config) -{ - VirtIOGPU *g = VIRTIO_GPU(vdev); - struct virtio_gpu_config vgconfig; - - memcpy(&vgconfig, config, sizeof(g->virtio_config)); - - if (vgconfig.events_clear) { - g->virtio_config.events_read &= ~vgconfig.events_clear; - } -} - -static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features, - Error **errp) -{ - VirtIOGPU *g = VIRTIO_GPU(vdev); - - if (virtio_gpu_virgl_enabled(g->conf)) { - features |= (1 << VIRTIO_GPU_F_VIRGL); - } - return features; -} - -static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features) -{ - static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); - VirtIOGPU *g = VIRTIO_GPU(vdev); - - g->use_virgl_renderer = ((features & virgl) == virgl); - trace_virtio_gpu_features(g->use_virgl_renderer); -} - -static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type) -{ - g->virtio_config.events_read |= event_type; - virtio_notify_config(&g->parent_obj); -} - static struct virtio_gpu_simple_resource * virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id) { @@ -229,21 +185,6 @@ void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g, virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp)); } -static void -virtio_gpu_fill_display_info(VirtIOGPU *g, - struct virtio_gpu_resp_display_info *dpy_info) -{ - int i; - - for (i = 0; i < g->conf.max_outputs; i++) { - if (g->enabled_output_bitmask & (1 << i)) { - dpy_info->pmodes[i].enabled = 1; - dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width); - dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height); - } - } -} - void virtio_gpu_get_display_info(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -252,7 +193,7 @@ void virtio_gpu_get_display_info(VirtIOGPU *g, trace_virtio_gpu_cmd_get_display_info(); memset(&display_info, 0, sizeof(display_info)); display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO; - virtio_gpu_fill_display_info(g, &display_info); + virtio_gpu_base_fill_display_info(VIRTIO_GPU_BASE(g), &display_info); virtio_gpu_ctrl_response(g, cmd, &display_info.hdr, sizeof(display_info)); } @@ -338,7 +279,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, } res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height); - if (res->hostmem + g->hostmem < g->conf.max_hostmem) { + if (res->hostmem + g->hostmem < g->conf_max_hostmem) { res->image = pixman_image_create_bits(pformat, c2d.width, c2d.height, @@ -484,7 +425,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, pixman_region_init_rect(&flush_region, rf.r.x, rf.r.y, rf.r.width, rf.r.height); - for (i = 0; i < g->conf.max_outputs; i++) { + for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { struct virtio_gpu_scanout *scanout; pixman_region16_t region, finalregion; pixman_box16_t *extents; @@ -492,7 +433,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, if (!(res->scanout_bitmask & (1 << i))) { continue; } - scanout = &g->scanout[i]; + scanout = &g->parent_obj.scanout[i]; pixman_region_init(&finalregion); pixman_region_init_rect(®ion, scanout->x, scanout->y, @@ -502,7 +443,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, pixman_region_translate(&finalregion, -scanout->x, -scanout->y); extents = pixman_region_extents(&finalregion); /* work out the area we need to update for each console */ - dpy_gfx_update(g->scanout[i].con, + dpy_gfx_update(g->parent_obj.scanout[i].con, extents->x1, extents->y1, extents->x2 - extents->x1, extents->y2 - extents->y1); @@ -533,16 +474,16 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, ss.r.width, ss.r.height, ss.r.x, ss.r.y); - if (ss.scanout_id >= g->conf.max_outputs) { + if (ss.scanout_id >= g->parent_obj.conf.max_outputs) { qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", __func__, ss.scanout_id); cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; return; } - g->enable = 1; + g->parent_obj.enable = 1; if (ss.resource_id == 0) { - scanout = &g->scanout[ss.scanout_id]; + scanout = &g->parent_obj.scanout[ss.scanout_id]; if (scanout->resource_id) { res = virtio_gpu_find_resource(g, scanout->resource_id); if (res) { @@ -556,7 +497,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; return; } - dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL); + dpy_gfx_replace_surface(g->parent_obj.scanout[ss.scanout_id].con, NULL); scanout->ds = NULL; scanout->width = 0; scanout->height = 0; @@ -586,7 +527,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, return; } - scanout = &g->scanout[ss.scanout_id]; + scanout = &g->parent_obj.scanout[ss.scanout_id]; format = pixman_image_get_format(res->image); bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8); @@ -609,7 +550,8 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, return; } pixman_image_unref(rect); - dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds); + dpy_gfx_replace_surface(g->parent_obj.scanout[ss.scanout_id].con, + scanout->ds); } res->scanout_bitmask |= (1 << ss.scanout_id); @@ -813,7 +755,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) while (!QTAILQ_EMPTY(&g->cmdq)) { cmd = QTAILQ_FIRST(&g->cmdq); - if (g->renderer_blocked) { + if (g->parent_obj.renderer_blocked) { break; } @@ -822,14 +764,14 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) g, cmd); QTAILQ_REMOVE(&g->cmdq, cmd, next); - if (virtio_gpu_stats_enabled(g->conf)) { + if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.requests++; } if (!cmd->finished) { QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next); g->inflight++; - if (virtio_gpu_stats_enabled(g->conf)) { + if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { if (g->stats.max_inflight < g->inflight) { g->stats.max_inflight = g->inflight; } @@ -841,6 +783,11 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) } } +static void virtio_gpu_gl_unblock(VirtIOGPUBase *g) +{ + virtio_gpu_process_cmdq(VIRTIO_GPU(g)); +} + static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIOGPU *g = VIRTIO_GPU(vdev); @@ -851,7 +798,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } #ifdef CONFIG_VIRGL - if (!g->renderer_inited && g->use_virgl_renderer) { + if (!g->renderer_inited && g->parent_obj.use_virgl_renderer) { virtio_gpu_virgl_init(g); g->renderer_inited = true; } @@ -869,7 +816,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) virtio_gpu_process_cmdq(g); #ifdef CONFIG_VIRGL - if (g->use_virgl_renderer) { + if (g->parent_obj.use_virgl_renderer) { virtio_gpu_virgl_fence_poll(g); } #endif @@ -878,7 +825,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) static void virtio_gpu_ctrl_bh(void *opaque) { VirtIOGPU *g = opaque; - virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq); + virtio_gpu_handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq); } static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) @@ -916,71 +863,9 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) static void virtio_gpu_cursor_bh(void *opaque) { VirtIOGPU *g = opaque; - virtio_gpu_handle_cursor(&g->parent_obj, g->cursor_vq); -} - -static void virtio_gpu_invalidate_display(void *opaque) -{ -} - -static void virtio_gpu_update_display(void *opaque) -{ -} - -static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata) -{ -} - -static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) -{ - VirtIOGPU *g = opaque; - - if (idx >= g->conf.max_outputs) { - return -1; - } - - g->req_state[idx].x = info->xoff; - g->req_state[idx].y = info->yoff; - g->req_state[idx].width = info->width; - g->req_state[idx].height = info->height; - - if (info->width && info->height) { - g->enabled_output_bitmask |= (1 << idx); - } else { - g->enabled_output_bitmask &= ~(1 << idx); - } - - /* send event to guest */ - virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY); - return 0; + virtio_gpu_handle_cursor(&g->parent_obj.parent_obj, g->cursor_vq); } -static void virtio_gpu_gl_block(void *opaque, bool block) -{ - VirtIOGPU *g = opaque; - - if (block) { - g->renderer_blocked++; - } else { - g->renderer_blocked--; - } - assert(g->renderer_blocked >= 0); - - if (g->renderer_blocked == 0) { - virtio_gpu_process_cmdq(g); - } -} - -const GraphicHwOps virtio_gpu_ops = { - .invalidate = virtio_gpu_invalidate_display, - .gfx_update = virtio_gpu_update_display, - .text_update = virtio_gpu_text_update, - .ui_info = virtio_gpu_ui_info, -#ifdef CONFIG_VIRGL - .gl_block = virtio_gpu_gl_block, -#endif -}; - static const VMStateDescription vmstate_virtio_gpu_scanout = { .name = "virtio-gpu-one-scanout", .version_id = 1, @@ -1003,10 +888,11 @@ static const VMStateDescription vmstate_virtio_gpu_scanouts = { .name = "virtio-gpu-scanouts", .version_id = 1, .fields = (VMStateField[]) { - VMSTATE_INT32(enable, struct VirtIOGPU), - VMSTATE_UINT32_EQUAL(conf.max_outputs, struct VirtIOGPU, NULL), - VMSTATE_STRUCT_VARRAY_UINT32(scanout, struct VirtIOGPU, - conf.max_outputs, 1, + VMSTATE_INT32(parent_obj.enable, struct VirtIOGPU), + VMSTATE_UINT32_EQUAL(parent_obj.conf.max_outputs, + struct VirtIOGPU, NULL), + VMSTATE_STRUCT_VARRAY_UINT32(parent_obj.scanout, struct VirtIOGPU, + parent_obj.conf.max_outputs, 1, vmstate_virtio_gpu_scanout, struct virtio_gpu_scanout), VMSTATE_END_OF_LIST() @@ -1116,8 +1002,8 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, /* load & apply scanout state */ vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1); - for (i = 0; i < g->conf.max_outputs; i++) { - scanout = &g->scanout[i]; + for (i = 0; i < g->parent_obj.conf.max_outputs; i++) { + scanout = &g->parent_obj.scanout[i]; if (!scanout->resource_id) { continue; } @@ -1146,117 +1032,54 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) VirtIODevice *vdev = VIRTIO_DEVICE(qdev); VirtIOGPU *g = VIRTIO_GPU(qdev); bool have_virgl; - Error *local_err = NULL; - int i; + int num_capsets = 0; - if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { - error_setg(errp, "virtio-gpu does not support vIOMMU yet"); - return; - } - - if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { - error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS); - return; - } - - g->use_virgl_renderer = false; #if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN) have_virgl = false; #else have_virgl = display_opengl; #endif if (!have_virgl) { - g->conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); - } - - if (virtio_gpu_virgl_enabled(g->conf)) { - error_setg(&g->migration_blocker, "virgl is not yet migratable"); - migrate_add_blocker(g->migration_blocker, &local_err); - if (local_err) { - error_propagate(errp, local_err); - error_free(g->migration_blocker); - return; - } + g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); } - g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); - virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, - sizeof(struct virtio_gpu_config)); - - g->req_state[0].width = g->conf.xres; - g->req_state[0].height = g->conf.yres; - - if (virtio_gpu_virgl_enabled(g->conf)) { - /* use larger control queue in 3d mode */ - g->ctrl_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb); - g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb); - #if defined(CONFIG_VIRGL) - g->virtio_config.num_capsets = virtio_gpu_virgl_get_num_capsets(g); -#else - g->virtio_config.num_capsets = 0; + num_capsets = virtio_gpu_virgl_get_num_capsets(g); #endif - } else { - g->ctrl_vq = virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl_cb); - g->cursor_vq = virtio_add_queue(vdev, 16, virtio_gpu_handle_cursor_cb); + + if (!virtio_gpu_base_device_realize(qdev, + num_capsets, + virtio_gpu_handle_ctrl_cb, + virtio_gpu_handle_cursor_cb, + errp)) { + return; } + g->ctrl_vq = virtio_get_queue(vdev, 0); + g->cursor_vq = virtio_get_queue(vdev, 1); g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g); g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g); QTAILQ_INIT(&g->reslist); QTAILQ_INIT(&g->cmdq); QTAILQ_INIT(&g->fenceq); - - g->enabled_output_bitmask = 1; - - for (i = 0; i < g->conf.max_outputs; i++) { - g->scanout[i].con = - graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g); - if (i > 0) { - dpy_gfx_replace_surface(g->scanout[i].con, NULL); - } - } -} - -static void virtio_gpu_device_unrealize(DeviceState *qdev, Error **errp) -{ - VirtIOGPU *g = VIRTIO_GPU(qdev); - if (g->migration_blocker) { - migrate_del_blocker(g->migration_blocker); - error_free(g->migration_blocker); - } -} - -static void virtio_gpu_instance_init(Object *obj) -{ } static void virtio_gpu_reset(VirtIODevice *vdev) { VirtIOGPU *g = VIRTIO_GPU(vdev); struct virtio_gpu_simple_resource *res, *tmp; - int i; - g->enable = 0; +#ifdef CONFIG_VIRGL + if (g->parent_obj.use_virgl_renderer) { + virtio_gpu_virgl_reset(g); + } +#endif QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { virtio_gpu_resource_destroy(g, res); } - for (i = 0; i < g->conf.max_outputs; i++) { - g->scanout[i].resource_id = 0; - g->scanout[i].width = 0; - g->scanout[i].height = 0; - g->scanout[i].x = 0; - g->scanout[i].y = 0; - g->scanout[i].ds = NULL; - } -#ifdef CONFIG_VIRGL - if (g->use_virgl_renderer) { - virtio_gpu_virgl_reset(g); - g->use_virgl_renderer = 0; - } -#endif + virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev)); } /* @@ -1287,17 +1110,15 @@ static const VMStateDescription vmstate_virtio_gpu = { }; static Property virtio_gpu_properties[] = { - DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1), - DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf.max_hostmem, + VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf), + DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem, 256 * 1024 * 1024), #ifdef CONFIG_VIRGL - DEFINE_PROP_BIT("virgl", VirtIOGPU, conf.flags, + DEFINE_PROP_BIT("virgl", VirtIOGPU, parent_obj.conf.flags, VIRTIO_GPU_FLAG_VIRGL_ENABLED, true), - DEFINE_PROP_BIT("stats", VirtIOGPU, conf.flags, + DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, VIRTIO_GPU_FLAG_STATS_ENABLED, false), #endif - DEFINE_PROP_UINT32("xres", VirtIOGPU, conf.xres, 1024), - DEFINE_PROP_UINT32("yres", VirtIOGPU, conf.yres, 768), DEFINE_PROP_END_OF_LIST(), }; @@ -1305,27 +1126,20 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass); + vgc->gl_unblock = virtio_gpu_gl_unblock; vdc->realize = virtio_gpu_device_realize; - vdc->unrealize = virtio_gpu_device_unrealize; - vdc->get_config = virtio_gpu_get_config; - vdc->set_config = virtio_gpu_set_config; - vdc->get_features = virtio_gpu_get_features; - vdc->set_features = virtio_gpu_set_features; - vdc->reset = virtio_gpu_reset; - set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); - dc->props = virtio_gpu_properties; dc->vmsd = &vmstate_virtio_gpu; - dc->hotpluggable = false; + dc->props = virtio_gpu_properties; } static const TypeInfo virtio_gpu_info = { .name = TYPE_VIRTIO_GPU, - .parent = TYPE_VIRTIO_DEVICE, + .parent = TYPE_VIRTIO_GPU_BASE, .instance_size = sizeof(VirtIOGPU), - .instance_init = virtio_gpu_instance_init, .class_init = virtio_gpu_class_init, }; @@ -1335,26 +1149,3 @@ static void virtio_register_types(void) } type_init(virtio_register_types) - -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) != 24); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) != 56); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) != 32); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) != 40); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) != 48); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) != 48); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) != 56); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) != 16); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) != 408); - -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) != 72); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) != 72); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) != 96); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) != 24); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) != 32); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) != 32); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) != 32); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) != 40); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) != 32); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) != 24); diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index baa74ba82c..98388762f6 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -22,8 +22,9 @@ typedef struct VirtIOVGA { static void virtio_vga_invalidate_display(void *opaque) { VirtIOVGA *vvga = opaque; + VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); - if (vvga->vdev.enable) { + if (g->enable) { virtio_gpu_ops.invalidate(&vvga->vdev); } else { vvga->vga.hw_ops->invalidate(&vvga->vga); @@ -33,8 +34,9 @@ static void virtio_vga_invalidate_display(void *opaque) static void virtio_vga_update_display(void *opaque) { VirtIOVGA *vvga = opaque; + VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); - if (vvga->vdev.enable) { + if (g->enable) { virtio_gpu_ops.gfx_update(&vvga->vdev); } else { vvga->vga.hw_ops->gfx_update(&vvga->vga); @@ -44,8 +46,9 @@ static void virtio_vga_update_display(void *opaque) static void virtio_vga_text_update(void *opaque, console_ch_t *chardata) { VirtIOVGA *vvga = opaque; + VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); - if (vvga->vdev.enable) { + if (g->enable) { if (virtio_gpu_ops.text_update) { virtio_gpu_ops.text_update(&vvga->vdev, chardata); } @@ -98,7 +101,7 @@ static const VMStateDescription vmstate_virtio_vga = { static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev); - VirtIOGPU *g = &vvga->vdev; + VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); VGACommonState *vga = &vvga->vga; Error *err = NULL; uint32_t offset; @@ -168,7 +171,9 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) static void virtio_vga_reset(DeviceState *dev) { VirtIOVGA *vvga = VIRTIO_VGA(dev); - vvga->vdev.enable = 0; + VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); + + g->enable = 0; vga_dirty_log_start(&vvga->vga); } diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index b5d97ab26d..d1d2711475 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -36,7 +36,7 @@ obj-$(CONFIG_VGA) += vga.o common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o -obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu.o virtio-gpu-3d.o +obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o virtio-gpu.o-cflags := $(VIRGL_CFLAGS) From patchwork Mon Jun 18 16:17:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931055 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418cKK4VBhz9s2t for ; Tue, 19 Jun 2018 02:40:37 +1000 (AEST) Received: from localhost ([::1]:35885 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUxCl-0001um-BD for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:40:35 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44192) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrP-0002Mj-F9 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwrL-0005OJ-EN for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:31 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45498 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwrL-0005OC-8R for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:27 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E1FCC7DAC3 for ; Mon, 18 Jun 2018 16:18:26 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5B9EF200AC23; Mon, 18 Jun 2018 16:18:26 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:28 +0200 Message-Id: <20180618161729.334-26-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:26 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 18 Jun 2018 16:18:26 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 25/26] virtio-gpu: split virtio-gpu-pci & virtio-vga X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add base classes that are common to vhost-user-gpu-pci and vhost-user-vga. Signed-off-by: Marc-André Lureau --- hw/display/virtio-vga.h | 22 +++++++ hw/virtio/virtio-pci.h | 16 ++--- hw/display/virtio-gpu-pci.c | 39 +++++++++--- hw/display/virtio-vga.c | 122 +++++++++++++++++++----------------- MAINTAINERS | 2 +- 5 files changed, 126 insertions(+), 75 deletions(-) create mode 100644 hw/display/virtio-vga.h diff --git a/hw/display/virtio-vga.h b/hw/display/virtio-vga.h new file mode 100644 index 0000000000..212624449c --- /dev/null +++ b/hw/display/virtio-vga.h @@ -0,0 +1,22 @@ +#ifndef VIRTIO_VGA_H_ +#define VIRTIO_VGA_H_ + +#include "hw/virtio/virtio-pci.h" +#include "vga_int.h" + +/* + * virtio-vga-base: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_VGA_BASE "virtio-vga-base" +#define VIRTIO_VGA_BASE(obj) \ + OBJECT_CHECK(VirtIOVGABase, (obj), TYPE_VIRTIO_VGA_BASE) + +typedef struct VirtIOVGABase { + VirtIOPCIProxy parent_obj; + + VirtIOGPUBase *vgpu; + VGACommonState vga; + MemoryRegion vga_mrs[3]; +} VirtIOVGABase; + +#endif /* VIRTIO_VGA_H_ */ diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index c7e28e1b9c..42240f47b3 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -386,17 +386,19 @@ struct VHostUserInputPCI { VHostUserInput vhi; }; + /* - * virtio-gpu-pci: This extends VirtioPCIProxy. + * virtio-gpu-pci-base: This extends VirtioPCIProxy. */ -#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci" -#define VIRTIO_GPU_PCI(obj) \ - OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI) +#define TYPE_VIRTIO_GPU_PCI_BASE "virtio-gpu-pci-base" +#define VIRTIO_GPU_PCI_BASE(obj) \ + OBJECT_CHECK(VirtIOGPUPCIBase, (obj), TYPE_VIRTIO_GPU_PCI_BASE) -struct VirtIOGPUPCI { +typedef struct VirtIOGPUPCIBase { VirtIOPCIProxy parent_obj; - VirtIOGPU vdev; -}; + + VirtIOGPUBase *vgpu; +} VirtIOGPUPCIBase; #ifdef CONFIG_VHOST_VSOCK /* diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index 741badd909..5db6ad890d 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -19,16 +19,16 @@ #include "hw/virtio/virtio-pci.h" #include "hw/virtio/virtio-gpu.h" -static Property virtio_gpu_pci_properties[] = { +static Property virtio_gpu_pci_base_properties[] = { DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), DEFINE_PROP_END_OF_LIST(), }; -static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { - VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev); - VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vgpu->vdev); - DeviceState *vdev = DEVICE(&vgpu->vdev); + VirtIOGPUPCIBase *vgpu = VIRTIO_GPU_PCI_BASE(vpci_dev); + VirtIOGPUBase *g = vgpu->vgpu; + DeviceState *vdev = DEVICE(g); int i; Error *local_error = NULL; @@ -48,37 +48,56 @@ static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } } -static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data) +static void virtio_gpu_pci_base_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); - dc->props = virtio_gpu_pci_properties; + dc->props = virtio_gpu_pci_base_properties; dc->hotpluggable = false; - k->realize = virtio_gpu_pci_realize; + k->realize = virtio_gpu_pci_base_realize; pcidev_k->class_id = PCI_CLASS_DISPLAY_OTHER; } +static const TypeInfo virtio_gpu_pci_base_info = { + .name = TYPE_VIRTIO_GPU_PCI_BASE, + .parent = TYPE_VIRTIO_PCI, + .instance_size = sizeof(VirtIOGPUPCIBase), + .class_init = virtio_gpu_pci_base_class_init, + .abstract = true +}; + +#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci" +#define VIRTIO_GPU_PCI(obj) \ + OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI) + +struct VirtIOGPUPCI { + VirtIOGPUPCIBase parent_obj; + VirtIOGPU vdev; +}; + static void virtio_gpu_initfn(Object *obj) { VirtIOGPUPCI *dev = VIRTIO_GPU_PCI(obj); virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU); + VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); } static const TypeInfo virtio_gpu_pci_info = { .name = TYPE_VIRTIO_GPU_PCI, - .parent = TYPE_VIRTIO_PCI, + .parent = TYPE_VIRTIO_GPU_PCI_BASE, .instance_size = sizeof(VirtIOGPUPCI), .instance_init = virtio_gpu_initfn, - .class_init = virtio_gpu_pci_class_init, }; static void virtio_gpu_pci_register_types(void) { + type_register_static(&virtio_gpu_pci_base_info); type_register_static(&virtio_gpu_pci_info); } + type_init(virtio_gpu_pci_register_types) diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 98388762f6..0c503460af 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -1,56 +1,41 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/pci/pci.h" -#include "vga_int.h" -#include "hw/virtio/virtio-pci.h" #include "qapi/error.h" +#include "virtio-vga.h" -/* - * virtio-vga: This extends VirtioPCIProxy. - */ -#define TYPE_VIRTIO_VGA "virtio-vga" -#define VIRTIO_VGA(obj) \ - OBJECT_CHECK(VirtIOVGA, (obj), TYPE_VIRTIO_VGA) - -typedef struct VirtIOVGA { - VirtIOPCIProxy parent_obj; - VirtIOGPU vdev; - VGACommonState vga; - MemoryRegion vga_mrs[3]; -} VirtIOVGA; - -static void virtio_vga_invalidate_display(void *opaque) +static void virtio_vga_base_invalidate_display(void *opaque) { - VirtIOVGA *vvga = opaque; - VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga = opaque; + VirtIOGPUBase *g = vvga->vgpu; if (g->enable) { - virtio_gpu_ops.invalidate(&vvga->vdev); + virtio_gpu_ops.invalidate(g); } else { vvga->vga.hw_ops->invalidate(&vvga->vga); } } -static void virtio_vga_update_display(void *opaque) +static void virtio_vga_base_update_display(void *opaque) { - VirtIOVGA *vvga = opaque; - VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga = opaque; + VirtIOGPUBase *g = vvga->vgpu; if (g->enable) { - virtio_gpu_ops.gfx_update(&vvga->vdev); + virtio_gpu_ops.gfx_update(g); } else { vvga->vga.hw_ops->gfx_update(&vvga->vga); } } -static void virtio_vga_text_update(void *opaque, console_ch_t *chardata) +static void virtio_vga_base_text_update(void *opaque, console_ch_t *chardata) { - VirtIOVGA *vvga = opaque; - VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga = opaque; + VirtIOGPUBase *g = vvga->vgpu; if (g->enable) { if (virtio_gpu_ops.text_update) { - virtio_gpu_ops.text_update(&vvga->vdev, chardata); + virtio_gpu_ops.text_update(g, chardata); } } else { if (vvga->vga.hw_ops->text_update) { @@ -59,49 +44,52 @@ static void virtio_vga_text_update(void *opaque, console_ch_t *chardata) } } -static int virtio_vga_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) +static int virtio_vga_base_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) { - VirtIOVGA *vvga = opaque; + VirtIOVGABase *vvga = opaque; + VirtIOGPUBase *g = vvga->vgpu; if (virtio_gpu_ops.ui_info) { - return virtio_gpu_ops.ui_info(&vvga->vdev, idx, info); + return virtio_gpu_ops.ui_info(g, idx, info); } return -1; } -static void virtio_vga_gl_block(void *opaque, bool block) +static void virtio_vga_base_gl_block(void *opaque, bool block) { - VirtIOVGA *vvga = opaque; + VirtIOVGABase *vvga = opaque; + VirtIOGPUBase *g = vvga->vgpu; if (virtio_gpu_ops.gl_block) { - virtio_gpu_ops.gl_block(&vvga->vdev, block); + virtio_gpu_ops.gl_block(g, block); } } -static const GraphicHwOps virtio_vga_ops = { - .invalidate = virtio_vga_invalidate_display, - .gfx_update = virtio_vga_update_display, - .text_update = virtio_vga_text_update, - .ui_info = virtio_vga_ui_info, - .gl_block = virtio_vga_gl_block, +static const GraphicHwOps virtio_vga_base_ops = { + .invalidate = virtio_vga_base_invalidate_display, + .gfx_update = virtio_vga_base_update_display, + .text_update = virtio_vga_base_text_update, + .ui_info = virtio_vga_base_ui_info, + .gl_block = virtio_vga_base_gl_block, }; -static const VMStateDescription vmstate_virtio_vga = { +static const VMStateDescription vmstate_virtio_vga_base = { .name = "virtio-vga", .version_id = 2, .minimum_version_id = 2, .fields = (VMStateField[]) { /* no pci stuff here, saving the virtio device will handle that */ - VMSTATE_STRUCT(vga, VirtIOVGA, 0, vmstate_vga_common, VGACommonState), + VMSTATE_STRUCT(vga, VirtIOVGABase, 0, + vmstate_vga_common, VGACommonState), VMSTATE_END_OF_LIST() } }; /* VGA device wrapper around PCI device around virtio GPU */ -static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { - VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev); - VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga = VIRTIO_VGA_BASE(vpci_dev); + VirtIOGPUBase *g = vvga->vgpu; VGACommonState *vga = &vvga->vga; Error *err = NULL; uint32_t offset; @@ -159,7 +147,7 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) vvga->vga_mrs, true); vga->con = g->scanout[0].con; - graphic_console_set_hwops(vga->con, &virtio_vga_ops, vvga); + graphic_console_set_hwops(vga->con, &virtio_vga_base_ops, vvga); for (i = 0; i < g->conf.max_outputs; i++) { object_property_set_link(OBJECT(g->scanout[i].con), @@ -168,56 +156,76 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } } -static void virtio_vga_reset(DeviceState *dev) +static void virtio_vga_base_reset(DeviceState *dev) { - VirtIOVGA *vvga = VIRTIO_VGA(dev); - VirtIOGPUBase *g = VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga = VIRTIO_VGA_BASE(dev); + VirtIOGPUBase *g = vvga->vgpu; g->enable = 0; vga_dirty_log_start(&vvga->vga); } -static Property virtio_vga_properties[] = { +static Property virtio_vga_base_properties[] = { DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), DEFINE_PROP_END_OF_LIST(), }; -static void virtio_vga_class_init(ObjectClass *klass, void *data) +static void virtio_vga_base_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); - dc->props = virtio_vga_properties; - dc->reset = virtio_vga_reset; - dc->vmsd = &vmstate_virtio_vga; + dc->props = virtio_vga_base_properties; + dc->reset = virtio_vga_base_reset; + dc->vmsd = &vmstate_virtio_vga_base; dc->hotpluggable = false; - k->realize = virtio_vga_realize; + k->realize = virtio_vga_base_realize; pcidev_k->romfile = "vgabios-virtio.bin"; pcidev_k->class_id = PCI_CLASS_DISPLAY_VGA; } +static TypeInfo virtio_vga_base_info = { + .name = TYPE_VIRTIO_VGA_BASE, + .parent = TYPE_VIRTIO_PCI, + .instance_size = sizeof(struct VirtIOVGABase), + .class_init = virtio_vga_base_class_init, + .abstract = true, +}; + +#define TYPE_VIRTIO_VGA "virtio-vga" + +#define VIRTIO_VGA(obj) \ + OBJECT_CHECK(VirtIOVGA, (obj), TYPE_VIRTIO_VGA) + +typedef struct VirtIOVGA { + VirtIOVGABase parent_obj; + + VirtIOGPU vdev; +} VirtIOVGA; + static void virtio_vga_inst_initfn(Object *obj) { VirtIOVGA *dev = VIRTIO_VGA(obj); virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU); + VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); } static TypeInfo virtio_vga_info = { .name = TYPE_VIRTIO_VGA, - .parent = TYPE_VIRTIO_PCI, + .parent = TYPE_VIRTIO_VGA_BASE, .instance_size = sizeof(struct VirtIOVGA), .instance_init = virtio_vga_inst_initfn, - .class_init = virtio_vga_class_init, }; static void virtio_vga_register_types(void) { + type_register_static(&virtio_vga_base_info); type_register_static(&virtio_vga_info); } diff --git a/MAINTAINERS b/MAINTAINERS index 5dc312f7de..c958fff474 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1336,7 +1336,7 @@ virtio-gpu M: Gerd Hoffmann S: Maintained F: hw/display/virtio-gpu* -F: hw/display/virtio-vga.c +F: hw/display/virtio-vga.* F: include/hw/virtio/virtio-gpu.h vhost-user-gpu From patchwork Mon Jun 18 16:17:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= X-Patchwork-Id: 931057 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 418cN94VH4z9s2t for ; Tue, 19 Jun 2018 02:43:05 +1000 (AEST) Received: from localhost ([::1]:35903 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUxF9-0003HR-BQ for incoming@patchwork.ozlabs.org; Mon, 18 Jun 2018 12:43:03 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44220) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fUwrT-0002Qt-U3 for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fUwrR-0005Te-Ik for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:35 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57736 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fUwrR-0005T6-Cy for qemu-devel@nongnu.org; Mon, 18 Jun 2018 12:18:33 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 16A8E402178A for ; Mon, 18 Jun 2018 16:18:33 +0000 (UTC) Received: from localhost (ovpn-112-20.ams2.redhat.com [10.36.112.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1D8667C39; Mon, 18 Jun 2018 16:18:27 +0000 (UTC) From: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= To: qemu-devel@nongnu.org Date: Mon, 18 Jun 2018 18:17:29 +0200 Message-Id: <20180618161729.334-27-marcandre.lureau@redhat.com> In-Reply-To: <20180618161729.334-1-marcandre.lureau@redhat.com> References: <20180618161729.334-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 18 Jun 2018 16:18:33 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 18 Jun 2018 16:18:33 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'marcandre.lureau@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 26/26] hw/display: add vhost-user-vga & gpu-pci X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , kraxel@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Add new virtio-gpu devices with a "vhost-user" property. Tthe associated vhost-user backend is used to handle the virtio rings and provide rendering results thanks to the vhost-user-gpu protocol. Example usage: -object vhost-user-backend,id=vug,cmd="./vhost-user-gpu" -device vhost-user-vga,vhost-user=vug Signed-off-by: Marc-André Lureau --- hw/virtio/virtio-pci.h | 1 + include/hw/virtio/virtio-gpu.h | 13 + hw/display/vhost-user-gpu-pci.c | 51 ++++ hw/display/vhost-user-gpu.c | 488 ++++++++++++++++++++++++++++++++ hw/display/vhost-user-vga.c | 52 ++++ vl.c | 1 + hw/display/Makefile.objs | 3 + 7 files changed, 609 insertions(+) create mode 100644 hw/display/vhost-user-gpu-pci.c create mode 100644 hw/display/vhost-user-gpu.c create mode 100644 hw/display/vhost-user-vga.c diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 42240f47b3..ec8eeb2a93 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -56,6 +56,7 @@ typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI; typedef struct VirtIOInputHostPCI VirtIOInputHostPCI; typedef struct VHostUserInputPCI VHostUserInputPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; +typedef struct VhostUserGPUPCI VhostUserGPUPCI; typedef struct VHostVSockPCI VHostVSockPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 4a17000ce4..c5648d426a 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -19,6 +19,7 @@ #include "ui/console.h" #include "hw/virtio/virtio.h" #include "qemu/log.h" +#include "sysemu/vhost-user-backend.h" #include "standard-headers/linux/virtio_gpu.h" @@ -39,6 +40,8 @@ #define VIRTIO_GPU(obj) \ OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU) +#define TYPE_VHOST_USER_GPU "vhost-user-gpu" + #define VIRTIO_ID_GPU 16 struct virtio_gpu_simple_resource { @@ -156,6 +159,16 @@ typedef struct VirtIOGPU { } stats; } VirtIOGPU; +typedef struct VhostUserGPU { + VirtIOGPUBase parent_obj; + + VhostUserBackend *vhost; + int vhost_gpu_fd; /* closed by the chardev */ + CharBackend vhost_chr; + QemuDmaBuf dmabuf[VIRTIO_GPU_MAX_SCANOUTS]; + bool backend_blocked; +} VhostUserGPU; + extern const GraphicHwOps virtio_gpu_ops; /* to share between PCI and VGA */ diff --git a/hw/display/vhost-user-gpu-pci.c b/hw/display/vhost-user-gpu-pci.c new file mode 100644 index 0000000000..2eef4982a2 --- /dev/null +++ b/hw/display/vhost-user-gpu-pci.c @@ -0,0 +1,51 @@ +/* + * vhost-user GPU PCI device + * + * Copyright Red Hat, Inc. 2018 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/virtio/virtio-pci.h" + +#define TYPE_VHOST_USER_GPU_PCI "vhost-user-gpu-pci" +#define VHOST_USER_GPU_PCI(obj) \ + OBJECT_CHECK(VhostUserGPUPCI, (obj), TYPE_VHOST_USER_GPU_PCI) + +struct VhostUserGPUPCI { + VirtIOGPUPCIBase parent_obj; + + VhostUserGPU vdev; +}; + +static void vhost_user_gpu_pci_initfn(Object *obj) +{ + VhostUserGPUPCI *dev = VHOST_USER_GPU_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_GPU); + + VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); + + object_property_add_alias(obj, "vhost-user", + OBJECT(&dev->vdev), "vhost-user", + &error_abort); +} + +static const TypeInfo vhost_user_gpu_pci_info = { + .name = TYPE_VHOST_USER_GPU_PCI, + .parent = TYPE_VIRTIO_GPU_PCI_BASE, + .instance_size = sizeof(VhostUserGPUPCI), + .instance_init = vhost_user_gpu_pci_initfn, +}; + +static void vhost_user_gpu_pci_register_types(void) +{ + type_register_static(&vhost_user_gpu_pci_info); +} + +type_init(vhost_user_gpu_pci_register_types) diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c new file mode 100644 index 0000000000..4ba5382b01 --- /dev/null +++ b/hw/display/vhost-user-gpu.c @@ -0,0 +1,488 @@ +/* + * vhost-user GPU Device + * + * Copyright Red Hat, Inc. 2018 + * + * Authors: + * Marc-André Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "hw/virtio/virtio-gpu.h" +#include "chardev/char-fe.h" +#include "qapi/error.h" + +#define VHOST_USER_GPU(obj) \ + OBJECT_CHECK(VhostUserGPU, (obj), TYPE_VHOST_USER_GPU) + +typedef enum VhostUserGpuRequest { + VHOST_USER_GPU_NONE = 0, + VHOST_USER_GPU_GET_PROTOCOL_FEATURES, + VHOST_USER_GPU_SET_PROTOCOL_FEATURES, + VHOST_USER_GPU_GET_DISPLAY_INFO, + VHOST_USER_GPU_CURSOR_POS, + VHOST_USER_GPU_CURSOR_POS_HIDE, + VHOST_USER_GPU_CURSOR_UPDATE, + VHOST_USER_GPU_SCANOUT, + VHOST_USER_GPU_UPDATE, + VHOST_USER_GPU_DMABUF_SCANOUT, + VHOST_USER_GPU_DMABUF_UPDATE, +} VhostUserGpuRequest; + +typedef struct VhostUserGpuDisplayInfoReply { + struct virtio_gpu_resp_display_info info; +} VhostUserGpuDisplayInfoReply; + +typedef struct VhostUserGpuCursorPos { + uint32_t scanout_id; + uint32_t x; + uint32_t y; +} QEMU_PACKED VhostUserGpuCursorPos; + +typedef struct VhostUserGpuCursorUpdate { + VhostUserGpuCursorPos pos; + uint32_t hot_x; + uint32_t hot_y; + uint32_t data[64 * 64]; +} QEMU_PACKED VhostUserGpuCursorUpdate; + +typedef struct VhostUserGpuScanout { + uint32_t scanout_id; + uint32_t width; + uint32_t height; +} QEMU_PACKED VhostUserGpuScanout; + +typedef struct VhostUserGpuUpdate { + uint32_t scanout_id; + uint32_t x; + uint32_t y; + uint32_t width; + uint32_t height; + uint8_t data[]; +} QEMU_PACKED VhostUserGpuUpdate; + +typedef struct VhostUserGpuDMABUFScanout { + uint32_t scanout_id; + uint32_t x; + uint32_t y; + uint32_t width; + uint32_t height; + uint32_t fd_width; + uint32_t fd_height; + uint32_t fd_stride; + uint32_t fd_flags; + int fd_drm_fourcc; +} QEMU_PACKED VhostUserGpuDMABUFScanout; + +typedef struct VhostUserGpuMsg { + uint32_t request; /* VhostUserGpuRequest */ + uint32_t size; /* the following payload size */ + union { + VhostUserGpuCursorPos cursor_pos; + VhostUserGpuCursorUpdate cursor_update; + VhostUserGpuScanout scanout; + VhostUserGpuUpdate update; + VhostUserGpuDMABUFScanout dmabuf_scanout; + uint64_t u64; + } payload; +} QEMU_PACKED VhostUserGpuMsg; + +static VhostUserGpuMsg m __attribute__ ((unused)); +#define VHOST_USER_GPU_HDR_SIZE (sizeof(m.request) + sizeof(m.size)) + +static void vhost_user_gpu_update_blocked(VhostUserGPU *g, bool blocked); + +static void +vhost_user_gpu_handle_cursor(VhostUserGPU *g, VhostUserGpuMsg *msg) +{ + VhostUserGpuCursorPos *pos = &msg->payload.cursor_pos; + struct virtio_gpu_scanout *s; + + if (pos->scanout_id >= g->parent_obj.conf.max_outputs) { + return; + } + s = &g->parent_obj.scanout[pos->scanout_id]; + + if (msg->request == VHOST_USER_GPU_CURSOR_UPDATE) { + VhostUserGpuCursorUpdate *up = &msg->payload.cursor_update; + if (!s->current_cursor) { + s->current_cursor = cursor_alloc(64, 64); + } + + s->current_cursor->hot_x = up->hot_x; + s->current_cursor->hot_y = up->hot_y; + + memcpy(s->current_cursor->data, up->data, + 64 * 64 * sizeof(uint32_t)); + + dpy_cursor_define(s->con, s->current_cursor); + } + + dpy_mouse_set(s->con, pos->x, pos->y, + msg->request != VHOST_USER_GPU_CURSOR_POS_HIDE); +} + +static void +vhost_user_gpu_unblock(VhostUserGPU *g) +{ + uint32_t ok; + + qemu_chr_fe_write(&g->vhost_chr, (uint8_t *)&ok, sizeof(ok)); + +} +static void +vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg) +{ + QemuConsole *con = NULL; + struct virtio_gpu_scanout *s; + + switch (msg->request) { + case VHOST_USER_GPU_GET_PROTOCOL_FEATURES: { + uint64_t u64 = 0; + qemu_chr_fe_write(&g->vhost_chr, (uint8_t *)&u64, sizeof(u64)); + break; + } + case VHOST_USER_GPU_SET_PROTOCOL_FEATURES: { + break; + } + case VHOST_USER_GPU_GET_DISPLAY_INFO: { + struct virtio_gpu_resp_display_info display_info = { 0, }; + display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO; + virtio_gpu_base_fill_display_info(VIRTIO_GPU_BASE(g), &display_info); + qemu_chr_fe_write(&g->vhost_chr, + (uint8_t *)&display_info, sizeof(display_info)); + break; + } + case VHOST_USER_GPU_SCANOUT: { + VhostUserGpuScanout *m = &msg->payload.scanout; + + if (m->scanout_id >= g->parent_obj.conf.max_outputs) { + return; + } + s = &g->parent_obj.scanout[m->scanout_id]; + con = s->con; + + s->ds = qemu_create_displaysurface(m->width, m->height); + if (!s->ds) { + return; + } + + dpy_gfx_replace_surface(con, s->ds); + break; + } + case VHOST_USER_GPU_DMABUF_SCANOUT: { + VhostUserGpuDMABUFScanout *m = &msg->payload.dmabuf_scanout; + int fd = qemu_chr_fe_get_msgfd(&g->vhost_chr); + QemuDmaBuf *dmabuf; + + if (m->scanout_id >= g->parent_obj.conf.max_outputs) { + if (fd >= 0) { + close(fd); + } + break; + } + + con = g->parent_obj.scanout[m->scanout_id].con; + dmabuf = &g->dmabuf[m->scanout_id]; + if (g->parent_obj.enable && dmabuf->fd >= 0) { + close(dmabuf->fd); + dmabuf->fd = -1; + } + dpy_gl_release_dmabuf(con, dmabuf); + if (fd == -1) { + dpy_gl_scanout_disable(con); + break; + } + *dmabuf = (QemuDmaBuf) { + .fd = fd, + .width = m->fd_width, + .height = m->fd_height, + .stride = m->fd_stride, + .fourcc = m->fd_drm_fourcc, + .y0_top = m->fd_flags & VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP, + }; + dpy_gl_scanout_dmabuf(con, dmabuf); + break; + } + case VHOST_USER_GPU_DMABUF_UPDATE: { + VhostUserGpuUpdate *m = &msg->payload.update; + + if (m->scanout_id >= g->parent_obj.conf.max_outputs || + !g->parent_obj.scanout[m->scanout_id].con) { + error_report("invalid scanout update: %d", m->scanout_id); + vhost_user_gpu_unblock(g); + break; + } + + con = g->parent_obj.scanout[m->scanout_id].con; + dpy_gl_update(con, m->x, m->y, m->width, m->height); + g->backend_blocked = true; + break; + } + case VHOST_USER_GPU_UPDATE: { + VhostUserGpuUpdate *m = &msg->payload.update; + + if (m->scanout_id >= g->parent_obj.conf.max_outputs) { + break; + } + s = &g->parent_obj.scanout[m->scanout_id]; + con = s->con; + pixman_image_t *image = + pixman_image_create_bits(PIXMAN_x8r8g8b8, + m->width, + m->height, + (uint32_t *)m->data, + m->width * 4); + + pixman_image_composite(PIXMAN_OP_SRC, + image, NULL, s->ds->image, + 0, 0, 0, 0, m->x, m->y, m->width, m->height); + + pixman_image_unref(image); + dpy_gfx_update(con, m->x, m->y, m->width, m->height); + break; + } + default: + g_warning("unhandled message %d %d", msg->request, msg->size); + } + + if (con && qemu_console_is_gl_blocked(con)) { + vhost_user_gpu_update_blocked(g, true); + } +} + +static void +vhost_user_gpu_chr_read(void *opaque) +{ + VhostUserGPU *g = opaque; + VhostUserGpuMsg *msg = NULL; + VhostUserGpuRequest request; + uint32_t size; + int r; + + r = qemu_chr_fe_read_all(&g->vhost_chr, + (uint8_t *)&request, sizeof(uint32_t)); + if (r != sizeof(uint32_t)) { + error_report("failed to read msg header: %d, %d", r, errno); + goto end; + } + + r = qemu_chr_fe_read_all(&g->vhost_chr, + (uint8_t *)&size, sizeof(uint32_t)); + if (r != sizeof(uint32_t)) { + error_report("failed to read msg size"); + goto end; + } + + msg = g_malloc(VHOST_USER_GPU_HDR_SIZE + size); + g_return_if_fail(msg != NULL); + + r = qemu_chr_fe_read_all(&g->vhost_chr, + (uint8_t *)&msg->payload, size); + if (r != size) { + error_report("failed to read msg payload %d != %d", r, size); + goto end; + } + + msg->request = request; + msg->size = size; + + if (request == VHOST_USER_GPU_CURSOR_UPDATE || + request == VHOST_USER_GPU_CURSOR_POS || + request == VHOST_USER_GPU_CURSOR_POS_HIDE) { + vhost_user_gpu_handle_cursor(g, msg); + } else { + vhost_user_gpu_handle_display(g, msg); + } + +end: + g_free(msg); +} + +static void +vhost_user_gpu_update_blocked(VhostUserGPU *g, bool blocked) +{ + qemu_set_fd_handler(g->vhost_gpu_fd, + blocked ? NULL : vhost_user_gpu_chr_read, NULL, g); +} + +static void +vhost_user_gpu_gl_unblock(VirtIOGPUBase *b) +{ + VhostUserGPU *g = VHOST_USER_GPU(b); + + if (g->backend_blocked) { + vhost_user_gpu_unblock(VHOST_USER_GPU(g)); + g->backend_blocked = false; + } + + vhost_user_gpu_update_blocked(VHOST_USER_GPU(g), false); +} + +static void +vhost_user_gpu_set_status(VirtIODevice *vdev, uint8_t val) +{ + VhostUserGPU *g = VHOST_USER_GPU(vdev); + + if (val & VIRTIO_CONFIG_S_DRIVER_OK && vdev->vm_running) { + vhost_user_backend_start(g->vhost); + } else { + /* TODO: forcefully gl unblock ? */ + vhost_user_backend_stop(g->vhost); + } +} + +static bool +vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) +{ + VhostUserGPU *g = VHOST_USER_GPU(vdev); + + return vhost_virtqueue_pending(&g->vhost->dev, idx); +} + +static void +vhost_user_gpu_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) +{ + VhostUserGPU *g = VHOST_USER_GPU(vdev); + + vhost_virtqueue_mask(&g->vhost->dev, vdev, idx, mask); +} + +static void +vhost_user_gpu_is_busy(const Object *obj, const char *name, + Object *val, Error **errp) +{ + VhostUserGPU *g = VHOST_USER_GPU(obj); + + if (g->vhost) { + error_setg(errp, "can't use already busy vhost-user"); + } else { + qdev_prop_allow_set_link_before_realize(obj, name, val, errp); + } +} + +static void +vhost_user_gpu_instance_init(Object *obj) +{ + VhostUserGPU *g = VHOST_USER_GPU(obj); + + object_property_add_link(obj, "vhost-user", TYPE_VHOST_USER_BACKEND, + (Object **)&g->vhost, + vhost_user_gpu_is_busy, + OBJ_PROP_LINK_STRONG, + &error_abort); +} + +static void +vhost_user_gpu_reset(VirtIODevice *vdev) +{ + VhostUserGPU *g = VHOST_USER_GPU(vdev); + + virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev)); + + vhost_user_backend_stop(g->vhost); +} + +static void +vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp) +{ + VhostUserGPU *g = VHOST_USER_GPU(qdev); + VirtIODevice *vdev = VIRTIO_DEVICE(g); + Chardev *chr; + int sv[2]; + uint32_t num_capsets; + + if (!g->vhost) { + error_setg(errp, "'vhost-user' property is required"); + return; + } + + if (vhost_user_backend_dev_init(g->vhost, vdev, 2, errp) < 0) { + return; + } + + if (virtio_has_feature(g->vhost->dev.features, VIRTIO_GPU_F_VIRGL)) { + g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED; + } + + if (vhost_user_gpu_get_num_capsets(&g->vhost->dev, &num_capsets) < 0) { + error_setg(errp, "Failed to get num-capsets"); + return; + } + + if (!virtio_gpu_base_device_realize(qdev, num_capsets, NULL, NULL, errp)) { + return; + } + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { + error_setg_errno(errp, errno, "socketpair() failed"); + return; + } + + chr = CHARDEV(object_new(TYPE_CHARDEV_SOCKET)); + if (!chr || qemu_chr_add_client(chr, sv[0]) == -1) { + error_setg(errp, "Failed to make socket chardev"); + goto err; + } + if (!qemu_chr_fe_init(&g->vhost_chr, chr, errp)) { + goto err; + } + if (vhost_user_gpu_set_socket(&g->vhost->dev, sv[1]) < 0) { + error_setg(errp, "Failed to set vhost-user-gpu socket"); + goto err; + } + + g->vhost_gpu_fd = sv[0]; + vhost_user_gpu_update_blocked(g, false); + close(sv[1]); + return; + +err: + close(sv[0]); + close(sv[1]); + if (chr) { + object_unref(OBJECT(chr)); + } +} + +static Property vhost_user_gpu_properties[] = { + VIRTIO_GPU_BASE_PROPERTIES(VhostUserGPU, parent_obj.conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void +vhost_user_gpu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass); + + vgc->gl_unblock = vhost_user_gpu_gl_unblock; + + vdc->realize = vhost_user_gpu_device_realize; + vdc->reset = vhost_user_gpu_reset; + vdc->set_status = vhost_user_gpu_set_status; + vdc->guest_notifier_mask = vhost_user_gpu_guest_notifier_mask; + vdc->guest_notifier_pending = vhost_user_gpu_guest_notifier_pending; + vdc->reset = vhost_user_gpu_reset; + + dc->props = vhost_user_gpu_properties; +} + +static const TypeInfo vhost_user_gpu_info = { + .name = TYPE_VHOST_USER_GPU, + .parent = TYPE_VIRTIO_GPU_BASE, + .instance_size = sizeof(VhostUserGPU), + .instance_init = vhost_user_gpu_instance_init, + .class_init = vhost_user_gpu_class_init, +}; + +static void vhost_user_gpu_register_types(void) +{ + type_register_static(&vhost_user_gpu_info); +} + +type_init(vhost_user_gpu_register_types) diff --git a/hw/display/vhost-user-vga.c b/hw/display/vhost-user-vga.c new file mode 100644 index 0000000000..0dec0c3d71 --- /dev/null +++ b/hw/display/vhost-user-vga.c @@ -0,0 +1,52 @@ +/* + * vhost-user VGA device + * + * Copyright Red Hat, Inc. 2018 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "virtio-vga.h" + +#define TYPE_VHOST_USER_VGA "vhost-user-vga" + +#define VHOST_USER_VGA(obj) \ + OBJECT_CHECK(VhostUserVGA, (obj), TYPE_VHOST_USER_VGA) + +typedef struct VhostUserVGA { + VirtIOVGABase parent_obj; + + VhostUserGPU vdev; +} VhostUserVGA; + +static void vhost_user_vga_inst_initfn(Object *obj) +{ + VhostUserVGA *dev = VHOST_USER_VGA(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_GPU); + + VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); + + object_property_add_alias(obj, "vhost-user", + OBJECT(&dev->vdev), "vhost-user", + &error_abort); +} + +static TypeInfo vhost_user_vga_info = { + .name = TYPE_VHOST_USER_VGA, + .parent = TYPE_VIRTIO_VGA_BASE, + .instance_size = sizeof(struct VhostUserVGA), + .instance_init = vhost_user_vga_inst_initfn, +}; + +static void vhost_user_vga_register_types(void) +{ + type_register_static(&vhost_user_vga_info); +} + +type_init(vhost_user_vga_register_types) diff --git a/vl.c b/vl.c index 1c21339ba7..3f620f56a7 100644 --- a/vl.c +++ b/vl.c @@ -235,6 +235,7 @@ static struct { { .driver = "vmware-svga", .flag = &default_vga }, { .driver = "qxl-vga", .flag = &default_vga }, { .driver = "virtio-vga", .flag = &default_vga }, + { .driver = "vhost-user-vga", .flag = &default_vga }, }; static QemuOptsList qemu_rtc_opts = { diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index d1d2711475..a98328d692 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -37,8 +37,11 @@ obj-$(CONFIG_VGA) += vga.o common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o +obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VHOST_USER)) += vhost-user-gpu.o obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o +obj-$(call land,$(CONFIG_VHOST_USER),$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI))) += vhost-user-gpu-pci.o obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o +obj-$(call land,$(CONFIG_VIRTIO_VGA),$(CONFIG_VHOST_USER)) += vhost-user-vga.o virtio-gpu.o-cflags := $(VIRGL_CFLAGS) virtio-gpu.o-libs += $(VIRGL_LIBS) virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS)