From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531487486379763.1957799331074; Fri, 13 Jul 2018 06:11:26 -0700 (PDT) Received: from localhost ([::1]:37236 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxr2-0004yY-M5 for importer@patchew.org; Fri, 13 Jul 2018 09:11:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40946) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxp4-0003f7-BR for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxp1-00015B-Ii for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:22 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57078 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 1fdxp1-00013l-D8 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:19 -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 1D1189BB6A for ; Fri, 13 Jul 2018 13:09:19 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id BA4122156889; Fri, 13 Jul 2018 13:09:18 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:48 +0200 Message-Id: <20180713130916.4153-2-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.1]); Fri, 13 Jul 2018 13:09:19 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 13 Jul 2018 13:09:19 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 01/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" 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=3D0x555556043062 "disc= onnected:", addr=3D0x0, is_listen=3Dfalse, is_telnet=3Dfalse) at /home/elma= rco/src/qq/chardev/char-socket.c:388 388 switch (addr->type) { (gdb) bt #0 0x0000555555d8c70c in SocketAddress_to_str (prefix=3D0x555556043062 "= disconnected:", addr=3D0x0, is_listen=3Dfalse, is_telnet=3Dfalse) at /home/= elmarco/src/qq/chardev/char-socket.c:388 #1 0x0000555555d8c8aa in update_disconnected_filename (s=3D0x555556b1ed0= 0) at /home/elmarco/src/qq/chardev/char-socket.c:419 #2 0x0000555555d8c959 in tcp_chr_disconnect (chr=3D0x555556b1ed00) at /h= ome/elmarco/src/qq/chardev/char-socket.c:438 #3 0x0000555555d8cba1 in tcp_chr_hup (channel=3D0x555556b75690, cond=3DG= _IO_HUP, opaque=3D0x555556b1ed00) at /home/elmarco/src/qq/chardev/char-sock= et.c:482 #4 0x0000555555da596e in qio_channel_fd_source_dispatch (source=3D0x5555= 56bb68b0, callback=3D0x555555d8cb58 , user_data=3D0x555556b1ed= 00) 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=C3=A9 Lureau Reviewed-by: Daniel P. Berrang=C3=A9 --- 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 efbad6ee7c..fa5bfb3b0e 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -419,8 +419,12 @@ static void update_disconnected_filename(SocketChardev= *s) Chardev *chr =3D CHARDEV(s); =20 g_free(chr->filename); - chr->filename =3D SocketAddress_to_str("disconnected:", s->addr, - s->is_listen, s->is_telnet); + if (s->addr) { + chr->filename =3D SocketAddress_to_str("disconnected:", s->addr, + s->is_listen, s->is_telnet); + } else { + chr->filename =3D g_strdup("disconnected:socket"); + } } =20 /* NB may be called even if tcp_chr_connect has not been --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531487493235966.6600539896526; Fri, 13 Jul 2018 06:11:33 -0700 (PDT) Received: from localhost ([::1]:37238 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxrA-000567-2E for importer@patchew.org; Fri, 13 Jul 2018 09:11:32 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40945) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxp4-0003f6-B7 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxp3-0001Ad-4q for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:22 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57084 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 1fdxp2-00018z-V3 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:21 -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 9E7DCBB41E for ; Fri, 13 Jul 2018 13:09:20 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 503012026D6B; Fri, 13 Jul 2018 13:09:20 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:49 +0200 Message-Id: <20180713130916.4153-3-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.1]); Fri, 13 Jul 2018 13:09:20 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 13 Jul 2018 13:09:20 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 02/29] chardev: remove qemu_chr_fe_read_all() counter 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" There is no obvious reason to have a loop counter. This limits from reading several megabytes large buffers in one go, since socket read/write usually have a limit. Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Paolo Bonzini Reviewed-by: Daniel P. Berrang=C3=A9 --- chardev/char-fe.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/chardev/char-fe.c b/chardev/char-fe.c index b1f228e8b5..f158f158f8 100644 --- a/chardev/char-fe.c +++ b/chardev/char-fe.c @@ -56,7 +56,7 @@ int qemu_chr_fe_write_all(CharBackend *be, const uint8_t = *buf, int len) int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len) { Chardev *s =3D be->chr; - int offset =3D 0, counter =3D 10; + int offset =3D 0; int res; =20 if (!s || !CHARDEV_GET_CLASS(s)->chr_sync_read) { @@ -88,10 +88,6 @@ int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, = int len) } =20 offset +=3D res; - - if (!counter--) { - break; - } } =20 if (qemu_chr_replay(s) && replay_mode =3D=3D REPLAY_MODE_RECORD) { --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531487489018891.093118688821; Fri, 13 Jul 2018 06:11:29 -0700 (PDT) Received: from localhost ([::1]:37237 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxr5-0004zh-NM for importer@patchew.org; Fri, 13 Jul 2018 09:11:27 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40962) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxp5-0003fE-LU for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxp4-0001Hg-NZ for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:23 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57088 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 1fdxp4-0001Fa-Ir for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:22 -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 459A3C12A5 for ; Fri, 13 Jul 2018 13:09:22 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id E64E02156889; Fri, 13 Jul 2018 13:09:21 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:50 +0200 Message-Id: <20180713130916.4153-4-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.1]); Fri, 13 Jul 2018 13:09:22 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 13 Jul 2018 13:09:22 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 03/29] chardev: unref if underlying chardev has no parent 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" It's possible to write code creating a chardev backend that is not registered. When it is not user-created, it makes sense to keep it hidden. Let the associated frontend destroy it also in this case. Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Daniel P. Berrang=C3=A9 --- chardev/char-fe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/chardev/char-fe.c b/chardev/char-fe.c index f158f158f8..a8931f7afd 100644 --- a/chardev/char-fe.c +++ b/chardev/char-fe.c @@ -235,7 +235,12 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del) d->backends[b->tag] =3D NULL; } if (del) { - object_unparent(OBJECT(b->chr)); + Object *obj =3D OBJECT(b->chr); + if (obj->parent) { + object_unparent(obj); + } else { + object_unref(obj); + } } b->chr =3D NULL; } --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531487552845735.5696422670301; Fri, 13 Jul 2018 06:12:32 -0700 (PDT) Received: from localhost ([::1]:37239 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxs7-0005zj-OH for importer@patchew.org; Fri, 13 Jul 2018 09:12:31 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40988) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpA-0003iJ-IV for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:31 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxp9-0001fL-Ip for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:28 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:51526 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 1fdxp9-0001dm-Co for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:27 -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 1D3E140122C8 for ; Fri, 13 Jul 2018 13:09:27 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 68B7023140; Fri, 13 Jul 2018 13:09:23 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:51 +0200 Message-Id: <20180713130916.4153-5-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.5]); Fri, 13 Jul 2018 13:09:27 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 13 Jul 2018 13:09:27 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 04/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Some scanouts during boot are top-down without it. y0_top is set from VHOST_USER_GPU_DMABUF_SCANOUT code path in the last patch of this series. In current QEMU code base, only vfio/display uses dmabuf API. But the VFIO query interface doesn't provide or need that detail so far. Signed-off-by: Marc-Andr=C3=A9 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; }; =20 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(DisplayChangeListene= r *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->hei= ght); ssd->guest_dmabuf_refresh =3D false; --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 153148767931993.41822416530499; Fri, 13 Jul 2018 06:14:39 -0700 (PDT) Received: from localhost ([::1]:37251 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxtv-0007Sc-3Q for importer@patchew.org; Fri, 13 Jul 2018 09:14:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41032) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpD-0003lO-Sv for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpB-0001lI-6u for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:31 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57100 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 1fdxpB-0001jq-0h for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:29 -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 A951EC12A5 for ; Fri, 13 Jul 2018 13:09:28 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3A4B72156889; Fri, 13 Jul 2018 13:09:28 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:52 +0200 Message-Id: <20180713130916.4153-6-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.1]); Fri, 13 Jul 2018 13:09:28 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 13 Jul 2018 13:09:28 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 05/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Take a VhostUserState* that can be pre-allocated, and initialize it with the associated chardev. Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Tiwei Bie --- 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 | 4 ++-- hw/virtio/vhost-user.c | 16 ++++++++++++---- net/vhost-user.c | 13 ++++--------- 9 files changed, 33 insertions(+), 66 deletions(-) diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-u= ser-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; =20 #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; =20 #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; =20 -VhostUserState *vhost_user_init(void); +bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp); void vhost_user_cleanup(VhostUserState *user); =20 #endif diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-use= r.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; =20 - VhostUserState *vhost_user; + VhostUserState vhost_user; CharBackend chr; char *chr_name; bool opened; @@ -104,7 +104,7 @@ cryptodev_vhost_user_start(int queues, continue; } =20 - options.opaque =3D s->vhost_user; + options.opaque =3D &s->vhost_user; options.backend_type =3D VHOST_BACKEND_TYPE_USER; options.cc =3D b->conf.peers.ccs[i]; s->vhost_crypto[i] =3D cryptodev_vhost_init(&options); @@ -187,7 +187,6 @@ static void cryptodev_vhost_user_init( size_t i; Error *local_err =3D NULL; Chardev *chr; - VhostUserState *user; CryptoDevBackendClient *cc; CryptoDevBackendVhostUser *s =3D CRYPTODEV_BACKEND_VHOST_USER(backend); @@ -218,15 +217,10 @@ static void cryptodev_vhost_user_init( } } =20 - user =3D vhost_user_init(); - if (!user) { - error_setg(errp, "Failed to init vhost_user"); + if (!vhost_user_init(&s->vhost_user, &s->chr, errp)) { return; } =20 - user->chr =3D &s->chr; - s->vhost_user =3D user; - qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, cryptodev_vhost_user_event, NULL, s, NULL, true); =20 @@ -312,11 +306,7 @@ static void cryptodev_vhost_user_cleanup( } } =20 - if (s->vhost_user) { - vhost_user_cleanup(s->vhost_user); - g_free(s->vhost_user); - s->vhost_user =3D NULL; - } + vhost_user_cleanup(&s->vhost_user); } =20 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 =3D VIRTIO_DEVICE(dev); VHostUserBlk *s =3D VHOST_USER_BLK(vdev); - VhostUserState *user; int i, ret; =20 if (!s->chardev.chr) { @@ -242,15 +241,10 @@ static void vhost_user_blk_device_realize(DeviceState= *dev, Error **errp) return; } =20 - user =3D 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; } =20 - user->chr =3D &s->chardev; - s->vhost_user =3D user; - virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, sizeof(struct virtio_blk_config)); =20 @@ -266,7 +260,7 @@ static void vhost_user_blk_device_realize(DeviceState *= dev, Error **errp) =20 vhost_dev_set_config_notifier(&s->dev, &blk_ops); =20 - ret =3D vhost_dev_init(&s->dev, s->vhost_user, VHOST_BACKEND_TYPE_USER= , 0); + ret =3D vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USE= R, 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 =3D NULL; + vhost_user_cleanup(&s->vhost_user); } =20 static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) @@ -306,12 +297,7 @@ static void vhost_user_blk_device_unrealize(DeviceStat= e *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 =3D NULL; - } + vhost_user_cleanup(&s->vhost_user); } =20 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, Err= or **errp) VirtIOSCSICommon *vs =3D VIRTIO_SCSI_COMMON(dev); VHostUserSCSI *s =3D VHOST_USER_SCSI(dev); VHostSCSICommon *vsc =3D VHOST_SCSI_COMMON(s); - VhostUserState *user; Error *err =3D NULL; int ret; =20 @@ -86,30 +85,24 @@ static void vhost_user_scsi_realize(DeviceState *dev, E= rror **errp) return; } =20 - user =3D 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 =3D &vs->conf.chardev; =20 vsc->dev.nvqs =3D 2 + vs->conf.num_queues; vsc->dev.vqs =3D g_new(struct vhost_virtqueue, vsc->dev.nvqs); vsc->dev.vq_index =3D 0; vsc->dev.backend_features =3D 0; =20 - ret =3D vhost_dev_init(&vsc->dev, user, + ret =3D 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; } =20 - s->vhost_user =3D user; - /* Channel and lun both are 0 for bootable vhost-user-scsi disk */ vsc->channel =3D 0; vsc->lun =3D 0; @@ -129,12 +122,7 @@ static void vhost_user_scsi_unrealize(DeviceState *dev= , Error **errp) g_free(vsc->dev.vqs); =20 virtio_scsi_common_unrealize(dev, errp); - - if (s->vhost_user) { - vhost_user_cleanup(s->vhost_user); - g_free(s->vhost_user); - s->vhost_user =3D NULL; - } + vhost_user_cleanup(&s->vhost_user); } =20 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..c175148fce 100644 --- a/hw/virtio/vhost-stub.c +++ b/hw/virtio/vhost-stub.c @@ -7,9 +7,9 @@ bool vhost_has_free_slot(void) return true; } =20 -VhostUserState *vhost_user_init(void) +bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) { - return NULL; + return false; } =20 void vhost_user_cleanup(VhostUserState *user) 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 vh= ost_dev *dev, return result; } =20 -VhostUserState *vhost_user_init(void) +bool vhost_user_init(VhostUserState *user, CharBackend *chr, Error **errp) { - VhostUserState *user =3D g_new0(struct VhostUserState, 1); - - return user; + if (user->chr) { + error_setg(errp, "Cannot initialize vhost-user state"); + return false; + } + user->chr =3D chr; + return true; } =20 void vhost_user_cleanup(VhostUserState *user) { int i; =20 + if (!user->chr) { + return; + } + for (i =3D 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 =3D NULL; } } + user->chr =3D NULL; } =20 const VhostOps user_ops =3D { diff --git a/net/vhost-user.c b/net/vhost-user.c index a39f9c9974..cea78b81f6 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -291,19 +291,14 @@ static int net_vhost_user_init(NetClientState *peer, = const char *device, { Error *err =3D NULL; NetClientState *nc, *nc0 =3D NULL; - VhostUserState *user =3D NULL; NetVhostUserState *s =3D NULL; + VhostUserState *user; int i; =20 assert(name); assert(queues > 0); =20 - user =3D vhost_user_init(); - if (!user) { - error_report("failed to init vhost_user"); - goto err; - } - + user =3D g_new0(struct VhostUserState, 1); for (i =3D 0; i < queues; i++) { nc =3D qemu_new_net_client(&net_vhost_user_info, peer, device, nam= e); snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s", @@ -312,11 +307,11 @@ static int net_vhost_user_init(NetClientState *peer, = const char *device, if (!nc0) { nc0 =3D nc; s =3D 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 =3D &s->chr; } s =3D DO_UPCAST(NetVhostUserState, nc, nc); s->vhost_user =3D user; --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531487718930140.6587497583704; Fri, 13 Jul 2018 06:15:18 -0700 (PDT) Received: from localhost ([::1]:37253 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxun-0008QP-Nh for importer@patchew.org; Fri, 13 Jul 2018 09:15:17 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41033) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpD-0003lT-TI for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpC-0001pr-RO for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:31 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:51530 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 1fdxpC-0001ou-M7 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:30 -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 60F9D401C090 for ; Fri, 13 Jul 2018 13:09:30 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0792A2026D6B; Fri, 13 Jul 2018 13:09:29 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:53 +0200 Message-Id: <20180713130916.4153-7-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:09:30 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 13 Jul 2018 13:09:30 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 06/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Since commit 2566378d6d13bf4d28c7770bdbda5f7682594bbe, libvhost-user no longer panics on disconnect (rc =3D=3D 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=C3=A9 Lureau Reviewed-by: Jens Freimann =20 --- 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: --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 153148791997687.04315941293885; Fri, 13 Jul 2018 06:18:39 -0700 (PDT) Received: from localhost ([::1]:37271 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxy3-0002Kn-1X for importer@patchew.org; Fri, 13 Jul 2018 09:18:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41065) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpF-0003oi-RB for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpE-0001up-Id for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:33 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57102 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 1fdxpE-0001ty-E1 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:32 -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 207CEC32E for ; Fri, 13 Jul 2018 13:09:32 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id BCBB22156889; Fri, 13 Jul 2018 13:09:31 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:54 +0200 Message-Id: <20180713130916.4153-8-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.1]); Fri, 13 Jul 2018 13:09:32 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 13 Jul 2018 13:09:32 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 07/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- 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 =3D &hdr; iov.iov_len =3D VHOST_USER_HDR_SIZE; =20 - size =3D recvmsg(u->slave_fd, &msgh, 0); + do { + size =3D recvmsg(u->slave_fd, &msgh, 0); + } while (size < 0 && (errno =3D=3D EINTR || errno =3D=3D EAGAIN)); + if (size !=3D VHOST_USER_HDR_SIZE) { error_report("Failed to read from slave."); goto err; @@ -1004,7 +1007,10 @@ static void slave_read(void *opaque) } =20 /* Read payload */ - size =3D read(u->slave_fd, &payload, hdr.size); + do { + size =3D read(u->slave_fd, &payload, hdr.size); + } while (size < 0 && (errno =3D=3D EINTR || errno =3D=3D EAGAIN)); + if (size !=3D 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 =3D &payload; iovec[1].iov_len =3D hdr.size; =20 - size =3D writev(u->slave_fd, iovec, ARRAY_SIZE(iovec)); + do { + size =3D writev(u->slave_fd, iovec, ARRAY_SIZE(iovec)); + } while (size < 0 && (errno =3D=3D EINTR || errno =3D=3D EAGAIN)); + if (size !=3D VHOST_USER_HDR_SIZE + hdr.size) { error_report("Failed to send msg reply to slave."); goto err; --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531487856797425.5138992983126; Fri, 13 Jul 2018 06:17:36 -0700 (PDT) Received: from localhost ([::1]:37269 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxx1-0001bq-Fj for importer@patchew.org; Fri, 13 Jul 2018 09:17:35 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41094) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpI-0003rg-60 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpG-0001yg-Bn for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:36 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:51532 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 1fdxpG-0001xG-3G for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:34 -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 C259640122C8 for ; Fri, 13 Jul 2018 13:09:33 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 409FE2026D6B; Fri, 13 Jul 2018 13:09:33 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:55 +0200 Message-Id: <20180713130916.4153-9-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:09:33 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 13 Jul 2018 13:09:33 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 08/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" 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=3Dchar0,path=3D/tmp/foo.sock -object vhost-user-backend,id=3Dvuid,chardev=3Dchar0. Signed-off-by: Marc-Andr=C3=A9 Lureau --- include/sysemu/vhost-user-backend.h | 60 +++++++ backends/vhost-user.c | 244 ++++++++++++++++++++++++++++ vl.c | 3 +- MAINTAINERS | 2 + backends/Makefile.objs | 3 +- qemu-options.hx | 20 +++ 6 files changed, 330 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-use= r-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=C3=A9 Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * 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_BAC= KEND) + +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..bf39c0751d --- /dev/null +++ b/backends/vhost-user.c @@ -0,0 +1,244 @@ +/* + * QEMU vhost-user backend + * + * Copyright (C) 2018 Red Hat Inc + * + * Authors: + * Marc-Andr=C3=A9 Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * 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 =3D vdev; + b->dev.nvqs =3D nvqs; + b->dev.vqs =3D g_new(struct vhost_virtqueue, nvqs); + + ret =3D vhost_dev_init(&b->dev, &b->vhost_user, VHOST_BACKEND_TYPE_USE= R, 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 =3D BUS(qdev_get_parent_bus(DEVICE(b->vdev))); + VirtioBusClass *k =3D 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 =3D vhost_dev_enable_notifiers(&b->dev, b->vdev); + if (ret < 0) { + return; + } + + ret =3D 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 =3D b->vdev->guest_features; + ret =3D 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 =3D 0; i < b->dev.nvqs; i++) { + vhost_virtqueue_mask(&b->dev, b->vdev, + b->dev.vq_index + i, false); + } + + b->started =3D 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 =3D BUS(qdev_get_parent_bus(DEVICE(b->vdev))); + VirtioBusClass *k =3D VIRTIO_BUS_GET_CLASS(qbus); + int ret =3D 0; + + if (!b->started) { + return; + } + + vhost_dev_stop(&b->dev, b->vdev); + + if (k->set_guest_notifiers) { + ret =3D k->set_guest_notifiers(qbus->parent, + b->dev.nvqs, false); + if (ret < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + } + } + assert(ret >=3D 0); + + vhost_dev_disable_notifiers(&b->dev, b->vdev); + b->started =3D false; +} + +static void +vhost_user_backend_complete(UserCreatable *uc, Error **errp) +{ + VhostUserBackend *b =3D VHOST_USER_BACKEND(uc); + Chardev *chr; + + if (!b->chr_name) { + error_setg(errp, "You must specificy 'chardev'."); + return; + } + + chr =3D qemu_chr_find(b->chr_name); + if (chr =3D=3D 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 =3D 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 =3D VHOST_USER_BACKEND(obj); + + if (b->completed) { + error_setg(errp, QERR_PERMISSION_DENIED); + } else { + g_free(b->chr_name); + b->chr_name =3D g_strdup(value); + } +} + +static char *get_chardev(Object *obj, Error **errp) +{ + VhostUserBackend *b =3D VHOST_USER_BACKEND(obj); + Chardev *chr =3D 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 =3D 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 =3D USER_CREATABLE_CLASS(oc); + + ucc->complete =3D vhost_user_backend_complete; + ucc->can_be_deleted =3D vhost_user_backend_can_be_deleted; +} + +static const TypeInfo vhost_user_backend_info =3D { + .name =3D TYPE_VHOST_USER_BACKEND, + .parent =3D TYPE_OBJECT, + .instance_size =3D sizeof(VhostUserBackend), + .instance_init =3D vhost_user_backend_init, + .instance_finalize =3D vhost_user_backend_finalize, + .class_size =3D sizeof(VhostUserBackendClass), + .class_init =3D vhost_user_backend_class_init, + .interfaces =3D (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 16b913f9d5..5272b4939f 100644 --- a/vl.c +++ b/vl.c @@ -2737,7 +2737,8 @@ static bool object_create_initial(const char *type) } =20 #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/MAINTAINERS b/MAINTAINERS index 20eef3cb61..dd8d07651f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1189,6 +1189,8 @@ M: Michael S. Tsirkin S: Supported F: hw/*/*vhost* F: docs/interop/vhost-user.txt +F: backends/vhost-user.c +F: include/sysemu/vhost-user-backend.h =20 virtio M: Michael S. Tsirkin 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 +=3D cryptodev-builtin.o ifeq ($(CONFIG_VIRTIO),y) common-obj-y +=3D cryptodev-vhost.o common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) +=3D \ - cryptodev-vhost-user.o + cryptodev-vhost-user.o \ + vhost-user.o endif =20 common-obj-$(CONFIG_LINUX) +=3D hostmem-memfd.o diff --git a/qemu-options.hx b/qemu-options.hx index 654e69cc3b..413b97d5e9 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4292,6 +4292,26 @@ secondary: If you want to know the detail of above command line, you can read the colo-compare git log. =20 +@item -object vhost-user-backend,id=3Did=3D@var{id},chardev=3D@var{chardev= id} + +Create a vhost-user-backend object that holds a connection to a +vhost-user backend and can be referenced from virtio/vhost-user +devices that support it. + +The @var{id} parameter is a unique ID that will be used to reference +this vhost-user backend from the @option{vhost-user} device. The +@var{chardev} parameter is the unique ID of a character device backend +that provides the connection to the vhost-user slave process. (Since 3.0) + +@example + + # qemu-system-x86_64 \ + [...] \ + -object vhost-user-backend,id=3Dvuid,chardev=3Dchar0 \ + -device vhost-user-input-pci,vhost-user=3Dvuid + [...] +@end example + @item -object cryptodev-backend-builtin,id=3D@var{id}[,queues=3D@var{queue= s}] =20 Creates a cryptodev backend which executes crypto opreation from --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531487664942262.1597791605885; Fri, 13 Jul 2018 06:14:24 -0700 (PDT) Received: from localhost ([::1]:37250 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxto-0007Ow-Rc for importer@patchew.org; Fri, 13 Jul 2018 09:14:16 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41104) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpJ-0003sn-9x for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpI-00026f-5z for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:37 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:51534 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 1fdxpH-00024i-VC for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:36 -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 A50A340122C8 for ; Fri, 13 Jul 2018 13:09:35 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3C41A23140; Fri, 13 Jul 2018 13:09:35 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:56 +0200 Message-Id: <20180713130916.4153-10-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.5]); Fri, 13 Jul 2018 13:09:35 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 13 Jul 2018 13:09:35 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 09/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Add a new function to let caller do some tuning thanks to a callback before exec(). Signed-off-by: Marc-Andr=C3=A9 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); =20 +/** + * 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, =20 #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 =3D -1; int stdinfd[2] =3D { -1, -1 }; @@ -104,6 +107,10 @@ qio_channel_command_new_spawn(const char *const argv[], close(devnull); } =20 + 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 */ =20 + +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) --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531487842007832.6857030434314; Fri, 13 Jul 2018 06:17:22 -0700 (PDT) Received: from localhost ([::1]:37267 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxwm-0001Sa-N8 for importer@patchew.org; Fri, 13 Jul 2018 09:17:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41123) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpP-0003yJ-Uo for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpO-0002Wy-MO for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:43 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40294 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 1fdxpO-0002Uu-GD for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:42 -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 139817DAC8 for ; Fri, 13 Jul 2018 13:09:42 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 18ADF10FFE50; Fri, 13 Jul 2018 13:09:36 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:57 +0200 Message-Id: <20180713130916.4153-11-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.2]); Fri, 13 Jul 2018 13:09:42 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Fri, 13 Jul 2018 13:09:42 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 10/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" An executable with its arguments may be given as 'cmd' property, ex: -object vhost-user-backend,id=3Dvui,cmd=3D"./vhost-user-input /dev/input..". The executable is then spawn and, by convention, the vhost-user socket is passed as fd=3D3. 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=C3=A9 Lureau --- backends/vhost-user.c | 96 ++++++++++++++++++++++++++++++++++++++----- qemu-options.hx | 12 ++++-- 2 files changed, 94 insertions(+), 14 deletions(-) diff --git a/backends/vhost-user.c b/backends/vhost-user.c index bf39c0751d..32d3ec0e8b 100644 --- a/backends/vhost-user.c +++ b/backends/vhost-user.c @@ -136,31 +136,105 @@ vhost_user_backend_stop(VhostUserBackend *b) b->started =3D false; } =20 +static void +pre_exec_cb(void *data) +{ + int *sv =3D data; + int maxfd =3D sysconf(_SC_OPEN_MAX); + int fd; + + dup2(sv[1], 3); + for (fd =3D 4; fd < maxfd; fd++) { + close(fd); + } +} + static void vhost_user_backend_complete(UserCreatable *uc, Error **errp) { VhostUserBackend *b =3D VHOST_USER_BACKEND(uc); Chardev *chr; + char **argv =3D NULL; =20 - if (!b->chr_name) { - error_setg(errp, "You must specificy 'chardev'."); + if (!!b->chr_name + !!b->cmd !=3D 1) { + error_setg(errp, "You may specificy only one of 'chardev' or 'cmd'= ."); return; } =20 - chr =3D qemu_chr_find(b->chr_name); - if (chr =3D=3D NULL) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Chardev '%s' not found", b->chr_name); - return; - } + if (b->chr_name) { + chr =3D qemu_chr_find(b->chr_name); + if (chr =3D=3D NULL) { + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Chardev '%s' not found", b->chr_name); + return; + } =20 - 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) =3D=3D -1) { + error_setg_errno(errp, errno, "socketpair() failed"); + goto end; + } + + chr =3D CHARDEV(object_new(TYPE_CHARDEV_SOCKET)); + if (!chr || qemu_chr_add_client(chr, sv[0]) =3D=3D -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 =3D 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 =3D QIO_CHANNEL(child); + + close(sv[1]); } =20 b->completed =3D 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 =3D VHOST_USER_BACKEND(obj); + + return g_strdup(b->cmd); +} + +static void set_cmd(Object *obj, const char *str, Error **errp) +{ + VhostUserBackend *b =3D VHOST_USER_BACKEND(obj); + + if (b->child) { + error_setg(errp, "cannot change property value"); + return; + } + + g_free(b->cmd); + b->cmd =3D g_strdup(str); } =20 static void set_chardev(Object *obj, const char *value, Error **errp) @@ -189,6 +263,7 @@ static char *get_chardev(Object *obj, Error **errp) =20 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= ); } =20 @@ -197,6 +272,7 @@ static void vhost_user_backend_finalize(Object *obj) VhostUserBackend *b =3D VHOST_USER_BACKEND(obj); =20 g_free(b->dev.vqs); + g_free(b->cmd); g_free(b->chr_name); =20 vhost_user_cleanup(&b->vhost_user); diff --git a/qemu-options.hx b/qemu-options.hx index 413b97d5e9..9243a5f8ab 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4292,16 +4292,20 @@ secondary: If you want to know the detail of above command line, you can read the colo-compare git log. =20 -@item -object vhost-user-backend,id=3Did=3D@var{id},chardev=3D@var{chardev= id} +@item -object vhost-user-backend,id=3Did=3D@var{id}[,chardev=3D@var{charde= vid},cmd=3D@var{cmd}] =20 Create a vhost-user-backend object that holds a connection to a vhost-user backend and can be referenced from virtio/vhost-user devices that support it. =20 The @var{id} parameter is a unique ID that will be used to reference -this vhost-user backend from the @option{vhost-user} device. The -@var{chardev} parameter is the unique ID of a character device backend -that provides the connection to the vhost-user slave process. (Since 3.0) +this vhost-user backend from the @option{vhost-user} device. + +You must specify either @var{chardev} or @var{cmd}. The @var{chardev} +parameter is the unique ID of a character device backend that provides +the connection to the vhost-user slave process. The @var{cmd} +parameter will simplify handling of the backend, by running the given +command and establishing the connection. (Since 3.1) =20 @example =20 --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488052992881.9539490033645; Fri, 13 Jul 2018 06:20:52 -0700 (PDT) Received: from localhost ([::1]:37286 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy0B-00046v-Ng for importer@patchew.org; Fri, 13 Jul 2018 09:20:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41135) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpR-0003yK-3M for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:46 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpQ-0002cD-4k for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:45 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:36302 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 1fdxpP-0002aB-Vm for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:44 -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 A13D940201A3 for ; Fri, 13 Jul 2018 13:09:43 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 53B1F2026D6B; Fri, 13 Jul 2018 13:09:43 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:58 +0200 Message-Id: <20180713130916.4153-12-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:09:43 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Fri, 13 Jul 2018 13:09:43 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 11/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Split vhost_user_read(), so only header can be read with vhost_user_read_header(). Signed-off-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Daniel P. Berrang=C3=A9 --- 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(); } =20 -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 =3D dev->opaque; CharBackend *chr =3D u->user->chr; @@ -221,7 +221,7 @@ static int vhost_user_read(struct vhost_dev *dev, Vhost= UserMsg *msg) if (r !=3D 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; } =20 /* validate received flags */ @@ -229,7 +229,21 @@ static int vhost_user_read(struct vhost_dev *dev, Vhos= tUserMsg *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 =3D dev->opaque; + CharBackend *chr =3D u->user->chr; + uint8_t *p =3D (uint8_t *) msg; + int r, size; + + if (vhost_user_read_header(dev, msg) < 0) { + return -1; } =20 /* validate message size is sane */ @@ -237,7 +251,7 @@ static int vhost_user_read(struct vhost_dev *dev, Vhost= UserMsg *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; } =20 if (msg->hdr.size) { @@ -247,14 +261,11 @@ static int vhost_user_read(struct vhost_dev *dev, Vho= stUserMsg *msg) if (r !=3D size) { error_report("Failed to read msg payload." " Read %d instead of %d.", r, msg->hdr.size); - goto fail; + return -1; } } =20 return 0; - -fail: - return -1; } =20 static int process_message_reply(struct vhost_dev *dev, --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488109124250.73872351302748; Fri, 13 Jul 2018 06:21:49 -0700 (PDT) Received: from localhost ([::1]:37291 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy13-0004rn-7L for importer@patchew.org; Fri, 13 Jul 2018 09:21:45 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41149) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpT-0003zU-2O for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:50 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpR-0002jx-RQ for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:47 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:50078 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 1fdxpR-0002i6-Le for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:45 -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 576808185343 for ; Fri, 13 Jul 2018 13:09:45 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id D69972156889; Fri, 13 Jul 2018 13:09:44 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:08:59 +0200 Message-Id: <20180713130916.4153-13-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:09:45 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 13 Jul 2018 13:09:45 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 12/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Ask vhost user input backend the list of virtio_input_config. Signed-off-by: Marc-Andr=C3=A9 Lureau --- contrib/libvhost-user/libvhost-user.h | 1 + include/hw/virtio/vhost-backend.h | 4 ++ hw/virtio/vhost-user.c | 59 +++++++++++++++++++++++++++ docs/interop/vhost-user.txt | 7 ++++ 4 files changed, 71 insertions(+) diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/= libvhost-user.h index 4aa55b4d2d..a4afbc3a46 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 =3D 28, VHOST_USER_POSTCOPY_LISTEN =3D 29, VHOST_USER_POSTCOPY_END =3D 30, + VHOST_USER_INPUT_GET_CONFIG =3D 31, VHOST_USER_MAX } VhostUserRequest; =20 diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-ba= ckend.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 =20 #include "exec/memory.h" +#include "standard-headers/linux/virtio_input.h" =20 typedef enum VhostBackendType { VHOST_BACKEND_TYPE_NONE =3D 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); =20 +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..0c6914fab7 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -89,6 +89,7 @@ typedef enum VhostUserRequest { VHOST_USER_POSTCOPY_ADVISE =3D 28, VHOST_USER_POSTCOPY_LISTEN =3D 29, VHOST_USER_POSTCOPY_END =3D 30, + VHOST_USER_INPUT_GET_CONFIG =3D 31, VHOST_USER_MAX } VhostUserRequest; =20 @@ -338,6 +339,64 @@ static int vhost_user_write(struct vhost_dev *dev, Vho= stUserMsg *msg, return 0; } =20 +static void *vhost_user_read_size(struct vhost_dev *dev, uint32_t size) +{ + struct vhost_user *u =3D dev->opaque; + CharBackend *chr =3D u->user->chr; + int r; + uint8_t *p =3D g_malloc(size); + + r =3D qemu_chr_fe_read_all(chr, p, size); + if (r !=3D 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 =3D NULL; + VhostUserMsg msg =3D { + .hdr.request =3D VHOST_USER_INPUT_GET_CONFIG, + .hdr.flags =3D 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 =3D vhost_user_read_size(dev, msg.hdr.size); + if (!p) { + goto err; + } + + if (msg.hdr.request !=3D 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 =3D 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 f59667f498..cba1ddde16 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. =20 + * VHOST_USER_INPUT_GET_CONFIG + Id: 31 + Master payload: N/A + Slave payload: (struct virtio_input_config)* + + Ask vhost user input backend the list of virtio_input_config. + Slave message types ------------------- =20 --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488040504741.1701006887141; Fri, 13 Jul 2018 06:20:40 -0700 (PDT) Received: from localhost ([::1]:37282 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxzu-0003wl-Cf for importer@patchew.org; Fri, 13 Jul 2018 09:20:34 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41177) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpW-00042w-CM for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpT-0002u1-FO for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:50 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40308 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 1fdxpT-0002rN-9t for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09: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 0937E79D36 for ; Fri, 13 Jul 2018 13:09:47 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id B072D2026D6B; Fri, 13 Jul 2018 13:09:46 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:00 +0200 Message-Id: <20180713130916.4153-14-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:09:47 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Fri, 13 Jul 2018 13:09:47 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 13/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Simplify the creation of FD sources for other users. Signed-off-by: Marc-Andr=C3=A9 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); =20 +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 =3D { }; =20 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; } =20 +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_c= b cb, void *pvt) g_assert(cb); =20 dev =3D container_of(vu_dev, VugDev, parent); - src =3D vug_source_new(vu_dev, fd, vu_evt, cb, pvt); + src =3D _vug_source_new(vu_dev, fd, vu_evt, cb, pvt); g_hash_table_replace(dev->fdmap, GINT_TO_POINTER(fd), src); } =20 @@ -141,7 +148,7 @@ vug_init(VugDev *dev, int socket, dev->fdmap =3D g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify) g_source_destroy); =20 - dev->src =3D vug_source_new(&dev->parent, socket, G_IO_IN, vug_watch, = NULL); + dev->src =3D _vug_source_new(&dev->parent, socket, G_IO_IN, vug_watch,= NULL); } =20 void --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488292660850.8791055068906; Fri, 13 Jul 2018 06:24:52 -0700 (PDT) Received: from localhost ([::1]:37308 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy3z-0007Bv-Mq for importer@patchew.org; Fri, 13 Jul 2018 09:24:47 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41189) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpX-000448-Ka for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpV-00039S-Da for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:51 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:50082 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 1fdxpV-00035L-4u for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:49 -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 D24E08185343 for ; Fri, 13 Jul 2018 13:09:48 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3F3DA2026D6B; Fri, 13 Jul 2018 13:09:48 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:01 +0200 Message-Id: <20180713130916.4153-15-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:09:48 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 13 Jul 2018 13:09:48 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 14/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Add a vhost-user input backend, 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=3Dvuid,cmd=3D"vhost-user-input /dev/input/eve= nt0" Signed-off-by: Marc-Andr=C3=A9 Lureau --- contrib/vhost-user-input/main.c | 379 +++++++++++++++++++++++++ MAINTAINERS | 1 + Makefile | 3 + Makefile.objs | 1 + configure | 3 + contrib/vhost-user-input/Makefile.objs | 1 + 6 files changed, 388 insertions(+) create mode 100644 contrib/vhost-user-input/main.c create mode 100644 contrib/vhost-user-input/Makefile.objs diff --git a/contrib/vhost-user-input/main.c b/contrib/vhost-user-input/mai= n.c new file mode 100644 index 0000000000..f0a58da2a8 --- /dev/null +++ b/contrib/vhost-user-input/main.c @@ -0,0 +1,379 @@ +/* + * 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 +#include + +#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" +#include "qapi/error.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 =3D &vi->dev.parent; + VuVirtq *vq =3D vu_get_queue(dev, 0); + VuVirtqElement *elem; + unsigned have, need; + int i, len; + + /* queue up events ... */ + if (vi->qindex =3D=3D vi->qsize) { + vi->qsize++; + vi->queue =3D realloc(vi->queue, vi->qsize * + sizeof(virtio_input_event)); + } + vi->queue[vi->qindex++] =3D *event; + + /* ... until we see a report sync ... */ + if (event->type !=3D htole16(EV_SYN) || + event->code !=3D htole16(SYN_REPORT)) { + return; + } + + /* ... then check available space ... */ + need =3D sizeof(virtio_input_event) * vi->qindex; + vu_queue_get_avail_bytes(dev, vq, &have, NULL, need, 0); + if (have < need) { + vi->qindex =3D 0; + g_warning("ENOSPC in vq, dropping events"); + return; + } + + /* ... and finally pass them to the guest */ + for (i =3D 0; i < vi->qindex; i++) { + elem =3D 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 =3D 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 =3D 0; +} + +static void +vi_evdev_watch(VuDev *dev, int condition, void *data) +{ + VuInput *vi =3D data; + int fd =3D vi->evdevfd; + + g_debug("Got evdev condition %x", condition); + + struct virtio_input_event virtio; + struct input_event evdev; + int rc; + + for (;;) { + rc =3D read(fd, &evdev, sizeof(evdev)); + if (rc !=3D sizeof(evdev)) { + break; + } + + g_debug("input %d %d %d", evdev.type, evdev.code, evdev.value); + + virtio.type =3D htole16(evdev.type); + virtio.code =3D htole16(evdev.code); + virtio.value =3D 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 =3D le16toh(event->type); + evdev.code =3D le16toh(event->code); + evdev.value =3D le32toh(event->value); + + rc =3D write(vi->evdevfd, &evdev, sizeof(evdev)); + if (rc =3D=3D -1) { + perror("vi_host_handle_status: write"); + } +} + +static void vi_handle_sts(VuDev *dev, int qidx) +{ + VuInput *vi =3D container_of(dev, VuInput, dev.parent); + VuVirtq *vq =3D vu_get_queue(dev, qidx); + virtio_input_event event; + VuVirtqElement *elem; + int len; + + g_debug("%s", G_STRFUNC); + + for (;;) { + elem =3D vu_queue_pop(dev, vq, sizeof(VuVirtqElement)); + if (!elem) { + break; + } + + memset(&event, 0, sizeof(event)); + len =3D 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 =3D container_of(dev, VuInput, dev.parent); + VuVirtq *vq =3D vu_get_queue(dev, qidx); + + g_debug("queue started %d:%d", qidx, started); + + if (qidx =3D=3D 0) { + if (started && !vi->evsrc) { + vi->evsrc =3D vug_source_new(&vi->dev, vi->evdevfd, + G_IO_IN, vi_evdev_watch, vi); + } else if (!started) { + g_source_destroy(vi->evsrc); + vi->evsrc =3D 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 =3D container_of(dev, VuInput, dev.parent); + + switch (vmsg->request) { + case VHOST_USER_INPUT_GET_CONFIG: + vmsg->size =3D vi->config->len * sizeof(virtio_input_config); + vmsg->data =3D g_memdup(vi->config->data, vmsg->size); + *do_reply =3D true; + return 1; + default: + return 0; + } +} + +static const VuDevIface vuiface =3D { + .queue_set_started =3D vi_queue_set_started, + .process_msg =3D vi_process_msg, +}; + +static void +vi_bits_config(VuInput *vi, int type, int count) +{ + virtio_input_config bits; + int rc, i, size =3D 0; + + memset(&bits, 0, sizeof(bits)); + rc =3D ioctl(vi->evdevfd, EVIOCGBIT(type, count / 8), bits.u.bitmap); + if (rc < 0) { + return; + } + + for (i =3D 0; i < count / 8; i++) { + if (bits.u.bitmap[i]) { + size =3D i + 1; + } + } + if (size =3D=3D 0) { + return; + } + + bits.select =3D VIRTIO_INPUT_CFG_EV_BITS; + bits.subsel =3D type; + bits.size =3D 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 =3D socket(AF_UNIX, SOCK_STREAM, 0); + if (sock <=3D 0) { + perror("socket"); + return -1; + } + + un.sun_family =3D AF_UNIX; + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + len =3D 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 int opt_fdnum =3D 3; +static char *opt_socket_path; +static gboolean opt_nograb; +static char *opt_pid_path; + +static GOptionEntry entries[] =3D { + { "no-grab", 'n', 0, G_OPTION_ARG_NONE, &opt_nograb, + "Don't grab device", NULL }, + { "pid", 'p', 0, G_OPTION_ARG_FILENAME, &opt_pid_path, + "PID path", "PATH" }, + { "fd", 'f', 0, G_OPTION_ARG_INT, &opt_fdnum, + "Use inherited fd socket", "FDNUM" }, + { "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 =3D NULL; + VuInput vi =3D { 0, }; + int rc, ver, fd; + virtio_input_config id; + struct input_id ids; + GError *error =3D NULL; + GOptionContext *context; + Error *err =3D NULL; + + context =3D 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(EXIT_FAILURE); + } + if (!opt_fname || !opt_fname[0] || opt_fname[1]) { + g_printerr("Please specify a single EVDEV filename\n"); + exit(EXIT_FAILURE); + } + + if (opt_pid_path && !qemu_write_pidfile(opt_pid_path, &err)) { + g_printerr("%s\n", error_get_pretty(err)); + error_free(err); + exit(EXIT_FAILURE); + } + + vi.evdevfd =3D open(opt_fname[0], O_RDWR); + if (vi.evdevfd < 0) { + g_printerr("Failed to open evdev: %s\n", g_strerror(errno)); + exit(EXIT_FAILURE); + } + + rc =3D ioctl(vi.evdevfd, EVIOCGVERSION, &ver); + if (rc < 0) { + g_printerr("%s: is not an evdev device\n", argv[1]); + exit(EXIT_FAILURE); + } + + if (!opt_nograb) { + rc =3D ioctl(vi.evdevfd, EVIOCGRAB, 1); + if (rc < 0) { + g_printerr("Failed to grab device\n"); + exit(EXIT_FAILURE); + } + } + + vi.config =3D 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 =3D VIRTIO_INPUT_CFG_ID_NAME; + id.size =3D strlen(id.u.string); + g_array_append_val(vi.config, id); + + if (ioctl(vi.evdevfd, EVIOCGID, &ids) =3D=3D 0) { + memset(&id, 0, sizeof(id)); + id.select =3D VIRTIO_INPUT_CFG_ID_DEVIDS; + id.size =3D sizeof(struct virtio_input_devids); + id.u.ids.bustype =3D cpu_to_le16(ids.bustype); + id.u.ids.vendor =3D cpu_to_le16(ids.vendor); + id.u.ids.product =3D cpu_to_le16(ids.product); + id.u.ids.version =3D 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 =3D unix_sock_new(opt_socket_path); + fd =3D accept(lsock, NULL, NULL); + close(lsock); + } else { + fd =3D opt_fdnum; + } + if (fd =3D=3D -1) { + g_printerr("Invalid socket"); + exit(EXIT_FAILURE); + } + vug_init(&vi.dev, fd, vi_panic, &vuiface); + + loop =3D 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/MAINTAINERS b/MAINTAINERS index dd8d07651f..ee13fe9ef1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1233,6 +1233,7 @@ M: Gerd Hoffmann S: Maintained F: hw/input/virtio-input*.c F: include/hw/virtio/virtio-input.h +F: contrib/vhost-user-input/* =20 virtio-serial M: Amit Shah diff --git a/Makefile b/Makefile index 2da686be33..0c61563d75 100644 --- a/Makefile +++ b/Makefile @@ -419,6 +419,7 @@ dummy :=3D $(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 \ @@ -717,6 +718,8 @@ vhost-user-scsi$(EXESUF): $(vhost-user-scsi-obj-y) libv= host-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 libqe= muutil.a + $(call LINK, $^) =20 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 :=3D $(LIBISCSI_CFLAGS) vhost-user-scsi.o-libs :=3D $(LIBISCSI_LIBS) vhost-user-scsi-obj-y =3D contrib/vhost-user-scsi/ vhost-user-blk-obj-y =3D contrib/vhost-user-blk/ +vhost-user-input-obj-y =3D contrib/vhost-user-input/ =20 ###################################################################### trace-events-subdirs =3D diff --git a/configure b/configure index 2a7796ea80..211301f497 100755 --- a/configure +++ b/configure @@ -5634,6 +5634,9 @@ if test "$want_tools" =3D "yes" ; then if [ "$ivshmem" =3D "yes" ]; then tools=3D"ivshmem-client\$(EXESUF) ivshmem-server\$(EXESUF) $tools" fi + if [ "$linux" =3D "yes" ] ; then + tools=3D"vhost-user-input\$(EXESUF) $tools" + fi fi if test "$softmmu" =3D yes ; then if test "$linux" =3D yes; then diff --git a/contrib/vhost-user-input/Makefile.objs b/contrib/vhost-user-in= put/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 =3D main.o --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488232920280.3986014444298; Fri, 13 Jul 2018 06:23:52 -0700 (PDT) Received: from localhost ([::1]:37305 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy35-0006Td-P0 for importer@patchew.org; Fri, 13 Jul 2018 09:23:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41205) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpZ-00044j-FG for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpX-0003Mj-9t for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:53 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:50084 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 1fdxpX-0003JK-3H for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09: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 B8B3B8185343 for ; Fri, 13 Jul 2018 13:09:50 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4BE7F2156889; Fri, 13 Jul 2018 13:09:49 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:02 +0200 Message-Id: <20180713130916.4153-16-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:09:50 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 13 Jul 2018 13:09:50 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 15/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Add a new virtio-input device, which connects to a vhost-user backend. Usage: -object vhost-user-backend,id=3Dvuid \ -device vhost-user-input-pci,vhost-user=3Dvuid Signed-off-by: Marc-Andr=C3=A9 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 { =20 #endif =20 +#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-in= put.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 =20 #include "ui/input.h" +#include "sysemu/vhost-user-backend.h" =20 /* ----------------------------------------------------------------- */ /* 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) =20 +#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; =20 struct VirtIOInputConfig { virtio_input_config config; @@ -98,6 +106,12 @@ struct VirtIOInputHost { int fd; }; =20 +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 =3D VHOST_USER_INPUT(dev); + VirtIOInput *vinput =3D VIRTIO_INPUT(dev); + VirtIODevice *vdev =3D 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) =3D=3D -1) { + return; + } + + ret =3D vhost_user_input_get_config(&vhi->vhost->dev, &config); + if (ret < 0) { + error_setg(errp, "failed to get input config"); + return; + } + for (i =3D 0; i < ret; i++) { + virtio_input_add_config(vinput, &config[i]); + } + g_free(config); +} + +static void vhost_input_change_active(VirtIOInput *vinput) +{ + VHostUserInput *vhi =3D 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 =3D { + .name =3D "vhost-user-input", + .unmigratable =3D 1, +}; + +static void vhost_input_class_init(ObjectClass *klass, void *data) +{ + VirtIOInputClass *vic =3D VIRTIO_INPUT_CLASS(klass); + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->vmsd =3D &vmstate_vhost_input; + vic->realize =3D vhost_input_realize; + vic->change_active =3D vhost_input_change_active; +} + +static void vhost_input_is_busy(const Object *obj, const char *name, + Object *val, Error **errp) +{ + VHostUserInput *vhi =3D 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 =3D VHOST_USER_INPUT(obj); + VirtIOInput *vinput =3D VIRTIO_INPUT(obj); + struct virtio_input_config vhost_input_config[] =3D { { /* 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 =3D { + .name =3D TYPE_VHOST_USER_INPUT, + .parent =3D TYPE_VIRTIO_INPUT, + .instance_size =3D sizeof(VHostUserInput), + .instance_init =3D vhost_input_init, + .class_init =3D 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 =3D { }; #endif =20 +static void vhost_input_pci_initfn(Object *obj) +{ + VHostUserInputPCI *dev =3D 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 =3D { + .name =3D TYPE_VHOST_USER_INPUT_PCI, + .parent =3D TYPE_VIRTIO_INPUT_PCI, + .instance_size =3D sizeof(VHostUserInputPCI), + .instance_init =3D vhost_input_pci_initfn, +}; + /* virtio-pci-bus */ =20 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 ee13fe9ef1..50ace65b3b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1231,6 +1231,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 F: contrib/vhost-user-input/* 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) +=3D virtio-input.o common-obj-$(CONFIG_VIRTIO_INPUT) +=3D virtio-input-hid.o ifeq ($(CONFIG_LINUX),y) common-obj-$(CONFIG_VIRTIO_INPUT) +=3D virtio-input-host.o +common-obj-$(call land,$(CONFIG_VHOST_USER),$(CONFIG_VIRTIO_INPUT)) +=3D v= host-user-input.o endif =20 obj-$(CONFIG_MILKYMIST) +=3D milkymist-softusb.o --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488405456522.992949035936; Fri, 13 Jul 2018 06:26:45 -0700 (PDT) Received: from localhost ([::1]:37324 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy5n-0000e7-Rt for importer@patchew.org; Fri, 13 Jul 2018 09:26:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41221) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpa-00046A-Vx for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpY-0003UW-VS for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:54 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:50086 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 1fdxpY-0003Sn-OH for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:52 -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 6A9588185343 for ; Fri, 13 Jul 2018 13:09:52 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id E6B512156889; Fri, 13 Jul 2018 13:09:51 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:03 +0200 Message-Id: <20180713130916.4153-17-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:09:52 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 13 Jul 2018 13:09:52 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 16/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Add a new vhost-user message to give a unix socket to a vhost-user backend for GPU display updates. 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, thus I chose to have a new dedicated channel. See vhost-user-gpu.rst for the protocol details. Signed-off-by: Marc-Andr=C3=A9 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.rst | 236 ++++++++++++++++++++++++++ docs/interop/vhost-user.txt | 9 + 6 files changed, 264 insertions(+) create mode 100644 docs/interop/vhost-user-gpu.rst diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/= libvhost-user.h index a4afbc3a46..42e227cce6 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 =3D 29, VHOST_USER_POSTCOPY_END =3D 30, VHOST_USER_INPUT_GET_CONFIG =3D 31, + VHOST_USER_GPU_SET_SOCKET =3D 32, VHOST_USER_MAX } VhostUserRequest; =20 diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-ba= ckend.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 *de= v, =20 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); =20 #endif /* VHOST_BACKEND_H */ diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 0c6914fab7..8c1a1742b0 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -90,6 +90,7 @@ typedef enum VhostUserRequest { VHOST_USER_POSTCOPY_LISTEN =3D 29, VHOST_USER_POSTCOPY_END =3D 30, VHOST_USER_INPUT_GET_CONFIG =3D 31, + VHOST_USER_GPU_SET_SOCKET =3D 32, VHOST_USER_MAX } VhostUserRequest; =20 @@ -397,6 +398,16 @@ err: return -1; } =20 +int vhost_user_gpu_set_socket(struct vhost_dev *dev, int fd) +{ + VhostUserMsg msg =3D { + .hdr.request =3D VHOST_USER_GPU_SET_SOCKET, + .hdr.flags =3D 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 50ace65b3b..5a83bf56a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1371,6 +1371,12 @@ F: hw/display/virtio-gpu* F: hw/display/virtio-vga.c F: include/hw/virtio/virtio-gpu.h =20 +vhost-user-gpu +M: Marc-Andr=C3=A9 Lureau +M: Gerd Hoffmann +S: Maintained +F: docs/interop/vhost-user-gpu.rst + Cirrus VGA M: Gerd Hoffmann S: Odd Fixes diff --git a/docs/interop/vhost-user-gpu.rst b/docs/interop/vhost-user-gpu.= rst new file mode 100644 index 0000000000..309d07fd6d --- /dev/null +++ b/docs/interop/vhost-user-gpu.rst @@ -0,0 +1,236 @@ +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Vhost-user-gpu Protocol +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +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 +=3D=3D=3D=3D=3D=3D=3D=3D + +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 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +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 reques= t. + + +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] cu= rsor | + -----------------------------------------------------------------------= ------ + +- 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-fo= urcc + + +In QEMU the vhost-user-gpu message is implemented with the following struc= t: + +:: + + 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 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +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 +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +- 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 cba1ddde16..c4c063a8c0 100644 --- a/docs/interop/vhost-user.txt +++ b/docs/interop/vhost-user.txt @@ -768,6 +768,15 @@ Master message types =20 Ask vhost user input backend the list of virtio_input_config. =20 + * VHOST_USER_GPU_SET_SOCKET + Id: 32 + Master payload: N/A + Slave 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.rst for details. + Slave message types ------------------- =20 --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488261250600.5400039099271; Fri, 13 Jul 2018 06:24:21 -0700 (PDT) Received: from localhost ([::1]:37306 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy3Y-0006sa-42 for importer@patchew.org; Fri, 13 Jul 2018 09:24:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41243) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxph-0004C7-1A for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:05 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpd-0003pc-Pz for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:00 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57112 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 1fdxpd-0003mm-KV for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:09:57 -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 50C27BB41E for ; Fri, 13 Jul 2018 13:09:57 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id A7A6C23140; Fri, 13 Jul 2018 13:09:53 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:04 +0200 Message-Id: <20180713130916.4153-18-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.1]); Fri, 13 Jul 2018 13:09:57 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 13 Jul 2018 13:09:57 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 17/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" See vhost-user.txt protocol documentation for details. Signed-off-by: Marc-Andr=C3=A9 Lureau --- contrib/libvhost-user/libvhost-user.h | 1 + include/hw/virtio/vhost-backend.h | 1 + hw/virtio/vhost-user.c | 15 +++++++++++++++ docs/interop/vhost-user.txt | 8 ++++++++ 4 files changed, 25 insertions(+) diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/= libvhost-user.h index 42e227cce6..9f30e05bd1 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 =3D 30, VHOST_USER_INPUT_GET_CONFIG =3D 31, VHOST_USER_GPU_SET_SOCKET =3D 32, + VHOST_USER_GPU_GET_NUM_CAPSETS =3D 33, VHOST_USER_MAX } VhostUserRequest; =20 diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-ba= ckend.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 *de= v, 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); =20 #endif /* VHOST_BACKEND_H */ diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 8c1a1742b0..bfec6528f2 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -91,6 +91,7 @@ typedef enum VhostUserRequest { VHOST_USER_POSTCOPY_END =3D 30, VHOST_USER_INPUT_GET_CONFIG =3D 31, VHOST_USER_GPU_SET_SOCKET =3D 32, + VHOST_USER_GPU_GET_NUM_CAPSETS =3D 33, VHOST_USER_MAX } VhostUserRequest; =20 @@ -922,6 +923,20 @@ static int vhost_user_get_u64(struct vhost_dev *dev, i= nt request, uint64_t *u64) return 0; } =20 +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 > INT32_MAX) { + return -1; + } + *num =3D u64; + return 0; +} + static int vhost_user_get_features(struct vhost_dev *dev, uint64_t *featur= es) { return vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features); diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt index c4c063a8c0..ba5e37d714 100644 --- a/docs/interop/vhost-user.txt +++ b/docs/interop/vhost-user.txt @@ -777,6 +777,14 @@ Master message types ancillary data. The GPU protocol is used to inform the master of rendering state and updates. See vhost-user-gpu.rst for details. =20 + * VHOST_USER_GPU_GET_NUM_CAPSETS + Id: 33 + Master payload: N/A + Slave payload: u64 + + Get the virtio-gpu 'num_capsets' config value. For non-virgl + rendering, the value can be 0. + Slave message types ------------------- =20 --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531487843213244.4296351376895; Fri, 13 Jul 2018 06:17:23 -0700 (PDT) Received: from localhost ([::1]:37268 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxwo-0001UC-1Z for importer@patchew.org; Fri, 13 Jul 2018 09:17:22 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41276) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpl-0004Fu-Dd for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:06 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpk-0004dk-8R for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:05 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40336 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 1fdxpk-0004av-2B for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:04 -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 BF6177DAC8 for ; Fri, 13 Jul 2018 13:10:03 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 931DD10FFE50; Fri, 13 Jul 2018 13:09:58 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:05 +0200 Message-Id: <20180713130916.4153-19-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.2]); Fri, 13 Jul 2018 13:10:03 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Fri, 13 Jul 2018 13:10:03 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 18/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The helper functions are useful to build the vhost-user-gpu backend. Signed-off-by: Marc-Andr=C3=A9 Lureau --- include/hw/virtio/virtio-gpu-bswap.h | 61 ++++++++++++++++++++++++++++ hw/display/virtio-gpu.c | 43 +------------------- 2 files changed, 62 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/virti= o-gpu-bswap.h new file mode 100644 index 0000000000..38d12160f6 --- /dev/null +++ b/include/hw/virtio/virtio-gpu-bswap.h @@ -0,0 +1,61 @@ +/* + * 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 late= r. + * See the COPYING file in the top-level directory. + */ + +#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 =3D (struct virtio_gpu_ctrl_hdr *) ptr; + + virtio_gpu_ctrl_hdr_bswap(hdr); + + i =3D sizeof(struct virtio_gpu_ctrl_hdr); + while (i < size) { + le32_to_cpus((uint32_t *)(ptr + i)); + i =3D 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 ec366f4c35..28602c1a35 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -19,6 +19,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" @@ -31,48 +32,6 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource= _id); =20 static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *= res); =20 -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 =3D (struct virtio_gpu_ctrl_hdr *) ptr; - - virtio_gpu_ctrl_hdr_bswap(hdr); - - i =3D sizeof(struct virtio_gpu_ctrl_hdr); - while (i < size) { - le32_to_cpus((uint32_t *)(ptr + i)); - i =3D 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, ...) \ --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488509655840.5074444010854; Fri, 13 Jul 2018 06:28:29 -0700 (PDT) Received: from localhost ([::1]:37338 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy7Y-0002F6-LV for importer@patchew.org; Fri, 13 Jul 2018 09:28:28 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41295) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpn-0004Hs-Bg for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpl-0004kV-R9 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:07 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:50108 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 1fdxpl-0004j9-Kl for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:05 -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 520F7818F71A for ; Fri, 13 Jul 2018 13:10:05 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id DD7C42026D76; Fri, 13 Jul 2018 13:10:04 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:06 +0200 Message-Id: <20180713130916.4153-20-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:10:05 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 13 Jul 2018 13:10:05 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 19/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" vhost-user-gpu will share the same code to open a DRM node. Signed-off-by: Marc-Andr=C3=A9 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 71b6a97bd1..4f475142fc 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" @@ -147,57 +145,12 @@ int qemu_egl_rn_fd; struct gbm_device *qemu_egl_rn_gbm_dev; EGLContext qemu_egl_rn_ctx; =20 -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 =3D opendir("/dev/dri"); - if (!dir) { - return -1; - } - - fd =3D -1; - while ((e =3D readdir(dir))) { - if (e->d_type !=3D DT_CHR) { - continue; - } - - if (strncmp(e->d_name, "renderD", 7)) { - continue; - } - - p =3D g_strdup_printf("/dev/dri/%s", e->d_name); - - r =3D open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); - if (r < 0) { - g_free(p); - continue; - } - fd =3D r; - g_free(p); - break; - } - - closedir(dir); - if (fd < 0) { - return -1; - } - return fd; -} - int egl_rendernode_init(const char *rendernode, DisplayGLMode mode) { qemu_egl_rn_fd =3D -1; int rc; =20 - qemu_egl_rn_fd =3D qemu_egl_rendernode_open(rendernode); + qemu_egl_rn_fd =3D qemu_drm_rendernode_open(rendernode); if (qemu_egl_rn_fd =3D=3D -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 =3D opendir("/dev/dri"); + if (!dir) { + return -1; + } + + fd =3D -1; + while ((e =3D readdir(dir))) { + if (e->d_type !=3D DT_CHR) { + continue; + } + + if (strncmp(e->d_name, "renderD", 7)) { + continue; + } + + p =3D g_strdup_printf("/dev/dri/%s", e->d_name); + + r =3D open(p, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK); + if (r < 0) { + g_free(p); + continue; + } + fd =3D r; + g_free(p); + break; + } + + closedir(dir); + if (fd < 0) { + return -1; + } + return fd; +} diff --git a/MAINTAINERS b/MAINTAINERS index 5a83bf56a3..01e2b47c34 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1565,6 +1565,7 @@ S: Odd Fixes F: ui/ F: include/ui/ F: qapi/ui.json +F: util/drm.c =20 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 +=3D stats64.o util-obj-y +=3D systemd.o util-obj-y +=3D iova-tree.o util-obj-$(CONFIG_LINUX) +=3D vfio-helpers.o +util-obj-$(CONFIG_LINUX) +=3D drm.o --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 153148854680023.84827722379066; Fri, 13 Jul 2018 06:29:06 -0700 (PDT) Received: from localhost ([::1]:37339 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy89-0002l1-Lb for importer@patchew.org; Fri, 13 Jul 2018 09:29:05 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41339) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpq-0004L3-LN for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:12 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpn-0004pJ-GT for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:10 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:50112 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 1fdxpn-0004oC-AJ for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:07 -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 02A5C818F6F8 for ; Fri, 13 Jul 2018 13:10:07 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8FBA72026D6B; Fri, 13 Jul 2018 13:10:06 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:07 +0200 Message-Id: <20180713130916.4153-21-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:10:07 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 13 Jul 2018 13:10:07 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 20/29] util: add qemu_write_pidfile() 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" There are variants of qemu_create_pidfile() in qemu-pr-helper and qemu-ga. Let's have a common implementation in libqemuutil. The code is based from pr-helper write_pidfile(), but allows the caller to deal with error reporting and behaviour. Signed-off-by: Marc-Andr=C3=A9 Lureau --- include/qemu/osdep.h | 3 ++- os-posix.c | 24 ------------------- os-win32.c | 25 -------------------- qga/main.c | 54 ++++++++----------------------------------- scsi/qemu-pr-helper.c | 40 ++++---------------------------- util/oslib-posix.c | 33 ++++++++++++++++++++++++++ util/oslib-win32.c | 27 ++++++++++++++++++++++ vl.c | 4 ++-- 8 files changed, 79 insertions(+), 131 deletions(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index a91068df0e..47fa570bd4 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -448,7 +448,8 @@ bool qemu_has_ofd_lock(void); #define FMT_pid "%d" #endif =20 -int qemu_create_pidfile(const char *filename); +bool qemu_write_pidfile(const char *pidfile, Error **errp); + int qemu_get_thread_id(void); =20 #ifndef CONFIG_IOVEC diff --git a/os-posix.c b/os-posix.c index 9ce6f74513..0e9403b4ff 100644 --- a/os-posix.c +++ b/os-posix.c @@ -352,30 +352,6 @@ void os_set_line_buffering(void) setvbuf(stdout, NULL, _IOLBF, 0); } =20 -int qemu_create_pidfile(const char *filename) -{ - char buffer[128]; - int len; - int fd; - - fd =3D qemu_open(filename, O_RDWR | O_CREAT, 0600); - if (fd =3D=3D -1) { - return -1; - } - if (lockf(fd, F_TLOCK, 0) =3D=3D -1) { - close(fd); - return -1; - } - len =3D snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid()); - if (write(fd, buffer, len) !=3D len) { - close(fd); - return -1; - } - - /* keep pidfile open & locked forever */ - return 0; -} - bool is_daemonized(void) { return daemonize; diff --git a/os-win32.c b/os-win32.c index 0674f94b57..0e0d7f50f3 100644 --- a/os-win32.c +++ b/os-win32.c @@ -97,28 +97,3 @@ int os_parse_cmd_args(int index, const char *optarg) { return -1; } - -int qemu_create_pidfile(const char *filename) -{ - char buffer[128]; - int len; - HANDLE file; - OVERLAPPED overlap; - BOOL ret; - memset(&overlap, 0, sizeof(overlap)); - - file =3D CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - if (file =3D=3D INVALID_HANDLE_VALUE) { - return -1; - } - len =3D snprintf(buffer, sizeof(buffer), "%d\n", getpid()); - ret =3D WriteFile(file, (LPCVOID)buffer, (DWORD)len, - NULL, &overlap); - CloseHandle(file); - if (ret =3D=3D 0) { - return -1; - } - return 0; -} diff --git a/qga/main.c b/qga/main.c index 537cc0e162..cc50692098 100644 --- a/qga/main.c +++ b/qga/main.c @@ -341,46 +341,6 @@ static FILE *ga_open_logfile(const char *logfile) return f; } =20 -#ifndef _WIN32 -static bool ga_open_pidfile(const char *pidfile) -{ - int pidfd; - char pidstr[32]; - - pidfd =3D qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); - if (pidfd =3D=3D -1 || lockf(pidfd, F_TLOCK, 0)) { - g_critical("Cannot lock pid file, %s", strerror(errno)); - if (pidfd !=3D -1) { - close(pidfd); - } - return false; - } - - if (ftruncate(pidfd, 0)) { - g_critical("Failed to truncate pid file"); - goto fail; - } - snprintf(pidstr, sizeof(pidstr), "%d\n", getpid()); - if (write(pidfd, pidstr, strlen(pidstr)) !=3D strlen(pidstr)) { - g_critical("Failed to write pid file"); - goto fail; - } - - /* keep pidfile open & locked forever */ - return true; - -fail: - unlink(pidfile); - close(pidfd); - return false; -} -#else /* _WIN32 */ -static bool ga_open_pidfile(const char *pidfile) -{ - return true; -} -#endif - static gint ga_strcmp(gconstpointer str1, gconstpointer str2) { return strcmp(str1, str2); @@ -480,8 +440,11 @@ void ga_unset_frozen(GAState *s) ga_enable_logging(s); g_warning("logging re-enabled due to filesystem unfreeze"); if (s->deferred_options.pid_filepath) { - if (!ga_open_pidfile(s->deferred_options.pid_filepath)) { - g_warning("failed to create/open pid file"); + Error *err =3D NULL; + + if (!qemu_write_pidfile(s->deferred_options.pid_filepath, &err)) { + g_warning("%s", error_get_pretty(err)); + error_free(err); } s->deferred_options.pid_filepath =3D NULL; } @@ -516,8 +479,11 @@ static void become_daemon(const char *pidfile) } =20 if (pidfile) { - if (!ga_open_pidfile(pidfile)) { - g_critical("failed to create pidfile"); + Error *err =3D NULL; + + if (!qemu_write_pidfile(pidfile, &err)) { + g_critical("%s", error_get_pretty(err)); + error_free(err); exit(EXIT_FAILURE); } } diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index 1528a712a0..cf6d360652 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -117,39 +117,6 @@ QEMU_COPYRIGHT "\n" , name); } =20 -static void write_pidfile(void) -{ - int pidfd; - char pidstr[32]; - - pidfd =3D qemu_open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); - if (pidfd =3D=3D -1) { - error_report("Cannot open pid file, %s", strerror(errno)); - exit(EXIT_FAILURE); - } - - if (lockf(pidfd, F_TLOCK, 0)) { - error_report("Cannot lock pid file, %s", strerror(errno)); - goto fail; - } - if (ftruncate(pidfd, 0)) { - error_report("Failed to truncate pid file"); - goto fail; - } - - snprintf(pidstr, sizeof(pidstr), "%d\n", getpid()); - if (write(pidfd, pidstr, strlen(pidstr)) !=3D strlen(pidstr)) { - error_report("Failed to write pid file"); - goto fail; - } - return; - -fail: - unlink(pidfile); - close(pidfd); - exit(EXIT_FAILURE); -} - /* SG_IO support */ =20 typedef struct PRHelperSGIOData { @@ -1076,8 +1043,11 @@ int main(int argc, char **argv) } } =20 - if (daemonize || pidfile_specified) - write_pidfile(); + if ((daemonize || pidfile_specified) && + !qemu_write_pidfile(pidfile, &local_err)) { + error_report_err(local_err); + exit(EXIT_FAILURE); + } =20 #ifdef CONFIG_LIBCAP if (drop_privileges() < 0) { diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 13b6f8d776..da1d4a3201 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -88,6 +88,39 @@ int qemu_daemon(int nochdir, int noclose) return daemon(nochdir, noclose); } =20 +bool qemu_write_pidfile(const char *pidfile, Error **errp) +{ + int pidfd; + char pidstr[32]; + + pidfd =3D qemu_open(pidfile, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (pidfd =3D=3D -1) { + error_setg_errno(errp, errno, "Cannot open pid file"); + return false; + } + + if (lockf(pidfd, F_TLOCK, 0)) { + error_setg_errno(errp, errno, "Cannot lock pid file"); + goto fail; + } + if (ftruncate(pidfd, 0)) { + error_setg_errno(errp, errno, "Failed to truncate pid file"); + goto fail; + } + + snprintf(pidstr, sizeof(pidstr), "%d\n", getpid()); + if (write(pidfd, pidstr, strlen(pidstr)) !=3D strlen(pidstr)) { + error_setg(errp, "Failed to write pid file"); + goto fail; + } + return true; + +fail: + unlink(pidfile); + close(pidfd); + return false; +} + void *qemu_oom_check(void *ptr) { if (ptr =3D=3D NULL) { diff --git a/util/oslib-win32.c b/util/oslib-win32.c index bb5ad28bd3..66d05c88e6 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -767,3 +767,30 @@ ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size= _t len, int flags, } return ret; } + +bool qemu_write_pidfile(const char *filename, Error **errp) +{ + char buffer[128]; + int len; + HANDLE file; + OVERLAPPED overlap; + BOOL ret; + memset(&overlap, 0, sizeof(overlap)); + + file =3D CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (file =3D=3D INVALID_HANDLE_VALUE) { + error_setg(errp, "Failed to create PID file"); + return false; + } + len =3D snprintf(buffer, sizeof(buffer), "%d\n", getpid()); + ret =3D WriteFile(file, (LPCVOID)buffer, (DWORD)len, + NULL, &overlap); + CloseHandle(file); + if (ret =3D=3D 0) { + error_setg(errp, "Failed to write PID file"); + return false; + } + return true; +} diff --git a/vl.c b/vl.c index 5272b4939f..8a9d3457ec 100644 --- a/vl.c +++ b/vl.c @@ -3993,8 +3993,8 @@ int main(int argc, char **argv, char **envp) os_daemonize(); rcu_disable_atfork(); =20 - if (pid_file && qemu_create_pidfile(pid_file) !=3D 0) { - error_report("could not acquire pid file: %s", strerror(errno)); + if (pid_file && !qemu_write_pidfile(pid_file, &err)) { + error_reportf_err(err, "cannot create PID file: "); exit(1); } =20 --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488427222361.7219031165523; Fri, 13 Jul 2018 06:27:07 -0700 (PDT) Received: from localhost ([::1]:37326 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy6E-00010U-6h for importer@patchew.org; Fri, 13 Jul 2018 09:27:06 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41340) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpq-0004L5-LN for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpo-0004tA-TC for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:10 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57132 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 1fdxpo-0004rx-Op for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:08 -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 70554BB41E for ; Fri, 13 Jul 2018 13:10:08 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1B3022156889; Fri, 13 Jul 2018 13:10:07 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:08 +0200 Message-Id: <20180713130916.4153-22-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.1]); Fri, 13 Jul 2018 13:10:08 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 13 Jul 2018 13:10:08 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 21/29] util: use fcntl() for qemu_write_pidfile() locking 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" According to Daniel Berrange, fcntl() locks have better portable semantics than lockf(). Use an exclusive lock on the first byte with fcntl(). Signed-off-by: Marc-Andr=C3=A9 Lureau --- util/oslib-posix.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/util/oslib-posix.c b/util/oslib-posix.c index da1d4a3201..26b11490b9 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -92,6 +92,11 @@ bool qemu_write_pidfile(const char *pidfile, Error **err= p) { int pidfd; char pidstr[32]; + struct flock lock =3D { + .l_type =3D F_WRLCK, + .l_whence =3D SEEK_SET, + .l_len =3D 1, + }; =20 pidfd =3D qemu_open(pidfile, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); if (pidfd =3D=3D -1) { @@ -99,10 +104,11 @@ bool qemu_write_pidfile(const char *pidfile, Error **e= rrp) return false; } =20 - if (lockf(pidfd, F_TLOCK, 0)) { + if (fcntl(pidfd, F_SETLK, &lock)) { error_setg_errno(errp, errno, "Cannot lock pid file"); goto fail; } + if (ftruncate(pidfd, 0)) { error_setg_errno(errp, errno, "Failed to truncate pid file"); goto fail; --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488805123754.0701762940448; Fri, 13 Jul 2018 06:33:25 -0700 (PDT) Received: from localhost ([::1]:37376 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdyCJ-0005pS-Bo for importer@patchew.org; Fri, 13 Jul 2018 09:33:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41409) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpy-0004YA-Eu for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpr-00058B-9B for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:18 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40358 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 1fdxpq-00054C-VZ for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10: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 A6A4A72632 for ; Fri, 13 Jul 2018 13:10:10 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id BA82910FFE50; Fri, 13 Jul 2018 13:10:09 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:09 +0200 Message-Id: <20180713130916.4153-23-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.2]); Fri, 13 Jul 2018 13:10:10 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Fri, 13 Jul 2018 13:10: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:'' Content-Transfer-Encoding: quoted-printable 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 v4 22/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" 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=3Dvug,cmd=3D"vhost-user-gpu" TODO: - add/check multi-head support - crash & resume handling - accelerated rendering/display to avoid the many round trips Signed-off-by: Marc-Andr=C3=A9 Lureau --- contrib/vhost-user-gpu/drm.h | 63 ++ contrib/vhost-user-gpu/virgl.h | 25 + contrib/vhost-user-gpu/vugpu.h | 168 ++++ contrib/vhost-user-gpu/drm.c | 190 +++++ contrib/vhost-user-gpu/main.c | 1164 ++++++++++++++++++++++++++ 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, 2237 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 late= r. + * 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=C3=A9 Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * 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..37e2bc9fcd --- /dev/null +++ b/contrib/vhost-user-gpu/vugpu.h @@ -0,0 +1,168 @@ +/* + * Virtio vhost-user GPU Device + * + * Copyright Red Hat, Inc. 2013-2018 + * + * Authors: + * Dave Airlie + * Gerd Hoffmann + * Marc-Andr=C3=A9 Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ +#ifndef VUGPU_H_ +#define VUGPU_H_ + +#include "qemu/osdep.h" + +#include "contrib/libvhost-user/libvhost-user-glib.h" +#include "standard-headers/linux/virtio_gpu.h" + +#include "qemu/queue.h" +#include "qemu/iov.h" +#include "qemu/bswap.h" +#include "drm.h" + +typedef enum VhostUserGpuRequest { + VHOST_USER_GPU_NONE =3D 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 =3D iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ + &out, sizeof(out)); \ + if (s !=3D 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 *a= b, + 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); + +int 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..c3691c35ba --- /dev/null +++ b/contrib/vhost-user-gpu/drm.c @@ -0,0 +1,190 @@ +/* + * Virtio vhost-user GPU Device + * + * DRM helpers + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * 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 =3D I915_TILING_NONE; + + buf->intel_bo =3D drm_intel_bo_alloc_tiled(buf->dev->bufmgr, "vhost-us= er-gpu", + buf->width, buf->height, + (buf->bpp / 8), &tiling, + &buf->stride, 0); + + if (!buf->intel_bo) { + return false; + } + + if (tiling !=3D 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) !=3D 0) { + return false; + } + + buf->mmap =3D 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 =3D drmGetVersion(fd); + + dev->fd =3D fd; + dev->name =3D strdup(version->name); + drmFreeVersion(version); + + if (0) { + /* nothing */ + } +#ifdef CONFIG_LIBDRM_INTEL + else if (!strcmp(dev->name, "i915")) { + dev->bufmgr =3D drm_intel_bufmgr_gem_init(fd, 32); + if (!dev->bufmgr) { + return false; + } + dev->alloc_bo =3D intel_alloc_bo; + dev->free_bo =3D intel_free_bo; + dev->export_bo_to_prime =3D intel_export_bo_to_prime; + dev->map_bo =3D intel_map_bo; + dev->unmap_bo =3D intel_unmap_bo; + dev->device_destroy =3D intel_device_destroy; + } +#endif + else { + g_warning("Error: drm device %s unsupported.", dev->name); + return false; + } + + dev->inited =3D true; + return true; +} + +static bool +drm_buffer_map(struct drm_buffer *buf) +{ + struct drm_device *dev =3D buf->dev; + + return dev->map_bo(buf); +} + +static void +drm_buffer_unmap(struct drm_buffer *buf) +{ + struct drm_device *dev =3D 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 =3D dev; + buffer->width =3D width; + buffer->height =3D height; + buffer->bpp =3D 32; + buffer->format =3D 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 =3D 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..911fa0af6d --- /dev/null +++ b/contrib/vhost-user-gpu/main.c @@ -0,0 +1,1164 @@ +/* + * Virtio vhost-user GPU Device + * + * Copyright Red Hat, Inc. 2013-2018 + * + * Authors: + * Dave Airlie + * Gerd Hoffmann + * Marc-Andr=C3=A9 Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + */ +#include "qemu/osdep.h" +#include "qemu/drm.h" +#include "qapi/error.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 int opt_fdnum =3D 3; +static char *opt_socket_path; +static char *opt_render_node; +static char *opt_pid_path; +static gboolean opt_virgl; + +static const char * +vg_cmd_to_string(int cmd) +{ +#define CMD(cmd) [cmd] =3D #cmd + static const char *vg_cmd_str[] =3D { + 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 >=3D 0 && cmd < G_N_ELEMENTS(vg_cmd_str)) { + return vg_cmd_str[cmd]; + } else { + return "unknown"; + } +} + +int +vg_sock_fd_read(int sock, void *buf, ssize_t buflen) +{ + int ret; + + do { + ret =3D read(sock, buf, buflen); + } while (ret < 0 && (errno =3D=3D EINTR || errno =3D=3D EAGAIN)); + + g_warn_if_fail(ret =3D=3D buflen); + return ret; +} + +static void +vg_sock_fd_close(VuGpu *g) +{ + if (g->sock_fd >=3D 0) { + close(g->sock_fd); + g->sock_fd =3D -1; + } +} + + +void +vg_wait_ok(VuGpu *g) +{ + uint32_t ok; + + if (vg_sock_fd_read(g->sock_fd, &ok, sizeof(ok)) < 0) { + vg_sock_fd_close(g); + } +} + +static int +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 =3D (void *)buf; + iov.iov_len =3D buflen; + + msg.msg_name =3D NULL; + msg.msg_namelen =3D 0; + msg.msg_iov =3D &iov; + msg.msg_iovlen =3D 1; + + if (fd !=3D -1) { + msg.msg_control =3D cmsgu.control; + msg.msg_controllen =3D sizeof(cmsgu.control); + + cmsg =3D CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len =3D CMSG_LEN(sizeof(int)); + cmsg->cmsg_level =3D SOL_SOCKET; + cmsg->cmsg_type =3D SCM_RIGHTS; + + *((int *)CMSG_DATA(cmsg)) =3D fd; + } else { + msg.msg_control =3D NULL; + msg.msg_controllen =3D 0; + } + + do { + ret =3D sendmsg(sock, &msg, 0); + } while (ret =3D=3D -1 && (errno =3D=3D EINTR || errno =3D=3D EAGAIN)); + + g_warn_if_fail(ret =3D=3D buflen); + return ret; +} + +void +vg_send_msg(VuGpu *vg, const VhostUserGpuMsg *msg, int fd) +{ + if (vg_sock_fd_write(vg->sock_fd, msg, + VHOST_USER_GPU_HDR_SIZE + msg->size, fd) < 0) { + vg_sock_fd_close(vg); + } +} + +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 =3D=3D 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 |=3D VIRTIO_GPU_FLAG_FENCE; + resp->fence_id =3D cmd->cmd_hdr.fence_id; + resp->ctx_id =3D cmd->cmd_hdr.ctx_id; + } + virtio_gpu_ctrl_hdr_bswap(resp); + s =3D iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_le= n); + if (s !=3D 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 =3D 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 =3D { + .type =3D 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 =3D { 0 ,}; + VhostUserGpuMsg msg =3D { + .request =3D VHOST_USER_GPU_GET_DISPLAY_INFO, + .size =3D 0, + }; + + vg_send_msg(vg, &msg, -1); + if (vg_sock_fd_read(vg->sock_fd, &dpy_info, sizeof(dpy_info)) < 0) { + vg_sock_fd_close(vg); + return; + } + + 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 =3D=3D 0) { + g_critical("%s: resource id 0 is not allowed", __func__); + cmd->error =3D VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + res =3D virtio_gpu_find_resource(g, c2d.resource_id); + if (res) { + g_critical("%s: resource already exists %d", __func__, c2d.resourc= e_id); + cmd->error =3D VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + res =3D g_new0(struct virtio_gpu_simple_resource, 1); + res->width =3D c2d.width; + res->height =3D c2d.height; + res->format =3D c2d.format; + res->resource_id =3D c2d.resource_id; + + pformat =3D 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 =3D VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + drm_buffer_create(&res->drm_buffer, &g->drm_dev, c2d.width, c2d.height= ); + res->image =3D 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 =3D VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY; + return; + } + + QTAILQ_INSERT_HEAD(&g->reslist, res, next); +} + +static void +vg_disable_scanout(VuGpu *g, int scanout_id) +{ + struct virtio_gpu_scanout *scanout =3D &g->scanout[scanout_id]; + struct virtio_gpu_simple_resource *res; + + if (scanout->resource_id =3D=3D 0) { + return; + } + + res =3D virtio_gpu_find_resource(g, scanout->resource_id); + if (res) { + res->scanout_bitmask &=3D ~(1 << scanout_id); + } + + scanout->width =3D 0; + scanout->height =3D 0; + + { + VhostUserGpuMsg msg =3D { + .request =3D VHOST_USER_GPU_SCANOUT, + .size =3D sizeof(VhostUserGpuScanout), + .payload.scanout.scanout_id =3D scanout_id, + }; + vg_send_msg(g, &msg, -1); + } +} + +static void +vg_resource_destroy(VuGpu *g, + struct virtio_gpu_simple_resource *res) +{ + int i; + + if (res->scanout_bitmask) { + for (i =3D 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) { + if (res->scanout_bitmask & (1 << i)) { + vg_disable_scanout(g, i); + } + } + } + + 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 =3D virtio_gpu_find_resource(g, unref.resource_id); + if (!res) { + g_critical("%s: illegal resource specified %d", + __func__, unref.resource_id); + cmd->error =3D 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 =3D sizeof(*ents) * ab->nr_entries; + ents =3D g_malloc(esize); + s =3D iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, + sizeof(*ab), ents, esize); + if (s !=3D esize) { + g_critical("%s: command data size incorrect %zu vs %zu", + __func__, s, esize); + g_free(ents); + return -1; + } + + *iov =3D g_malloc0(sizeof(struct iovec) * ab->nr_entries); + for (i =3D 0; i < ab->nr_entries; i++) { + uint64_t len =3D ents[i].length; + (*iov)[i].iov_len =3D ents[i].length; + (*iov)[i].iov_base =3D vu_gpa_to_va(&g->dev.parent, &len, ents[i].= addr); + if (!(*iov)[i].iov_base || len !=3D ents[i].length) { + g_critical("%s: resource %d element %d", + __func__, ab->resource_id, i); + g_free(*iov); + g_free(ents); + *iov =3D 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 =3D virtio_gpu_find_resource(g, ab.resource_id); + if (!res) { + g_critical("%s: illegal resource specified %d", + __func__, ab.resource_id); + cmd->error =3D VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + ret =3D vg_create_mapping_iov(g, &ab, cmd, &res->iov); + if (ret !=3D 0) { + cmd->error =3D VIRTIO_GPU_RESP_ERR_UNSPEC; + return; + } + + res->iov_cnt =3D 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 =3D 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 =3D VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + g_free(res->iov); + res->iov =3D NULL; + res->iov_cnt =3D 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 =3D 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 =3D 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 =3D VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + format =3D pixman_image_get_format(res->image); + bpp =3D (PIXMAN_FORMAT_BPP(format) + 7) / 8; + stride =3D pixman_image_get_stride(res->image); + + if (t2d.offset || t2d.r.x || t2d.r.y || + t2d.r.width !=3D pixman_image_get_width(res->image)) { + void *img_data =3D pixman_image_get_data(res->image); + for (h =3D 0; h < t2d.r.height; h++) { + src_offset =3D t2d.offset + stride * h; + dst_offset =3D (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, *ores; + 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 >=3D VIRTIO_GPU_MAX_SCANOUTS) { + g_critical("%s: illegal scanout id specified %d", + __func__, ss.scanout_id); + cmd->error =3D VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + + if (ss.resource_id =3D=3D 0) { + vg_disable_scanout(g, ss.scanout_id); + return; + } + + /* create a surface for this scanout */ + res =3D virtio_gpu_find_resource(g, ss.resource_id); + if (!res) { + g_critical("%s: illegal resource specified %d", + __func__, ss.resource_id); + cmd->error =3D 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 =3D VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; + return; + } + + scanout =3D &g->scanout[ss.scanout_id]; + + ores =3D virtio_gpu_find_resource(g, scanout->resource_id); + if (ores) { + ores->scanout_bitmask &=3D ~(1 << ss.scanout_id); + } + + res->scanout_bitmask |=3D (1 << ss.scanout_id); + scanout->resource_id =3D ss.resource_id; + scanout->x =3D ss.r.x; + scanout->y =3D ss.r.y; + scanout->width =3D ss.r.width; + scanout->height =3D ss.r.height; + + if (res->drm_buffer.mmap) { + struct drm_buffer *buffer =3D &res->drm_buffer; + VhostUserGpuMsg msg =3D { + .request =3D VHOST_USER_GPU_DMABUF_SCANOUT, + .size =3D sizeof(VhostUserGpuDMABUFScanout), + .payload.dmabuf_scanout.scanout_id =3D ss.scanout_id, + .payload.dmabuf_scanout.x =3D ss.r.x, + .payload.dmabuf_scanout.y =3D ss.r.y, + .payload.dmabuf_scanout.width =3D ss.r.width, + .payload.dmabuf_scanout.height =3D ss.r.height, + .payload.dmabuf_scanout.fd_width =3D buffer->width, + .payload.dmabuf_scanout.fd_height =3D buffer->height, + .payload.dmabuf_scanout.fd_stride =3D buffer->stride, + .payload.dmabuf_scanout.fd_drm_fourcc =3D buffer->format + }; + int fd; + + if (drm_buffer_get_dmabuf_fd(buffer, &fd)) { + vg_send_msg(g, &msg, fd); + close(fd); + } + } else { + VhostUserGpuMsg msg =3D { + .request =3D VHOST_USER_GPU_SCANOUT, + .size =3D sizeof(VhostUserGpuScanout), + .payload.scanout.scanout_id =3D ss.scanout_id, + .payload.scanout.width =3D scanout->width, + .payload.scanout.height =3D scanout->height + }; + vg_send_msg(g, &msg, -1); + /* TODO: VHOST_USER_GPU_UPDATE with associated resource ? */ + } +} + +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 =3D virtio_gpu_find_resource(g, rf.resource_id); + if (!res) { + g_critical("%s: illegal resource specified %d\n", + __func__, rf.resource_id); + cmd->error =3D 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 =3D 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 =3D 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 =3D &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 =3D pixman_region_extents(&finalregion); + size_t width =3D extents->x2 - extents->x1; + size_t height =3D extents->y2 - extents->y1; + + if (res->drm_buffer.mmap) { + VhostUserGpuMsg vmsg =3D { + .request =3D VHOST_USER_GPU_DMABUF_UPDATE, + .size =3D sizeof(VhostUserGpuUpdate), + .payload.update.scanout_id =3D i, + .payload.update.x =3D extents->x1, + .payload.update.y =3D extents->y1, + .payload.update.width =3D width, + .payload.update.height =3D height + }; + vg_send_msg(g, &vmsg, -1); + vg_wait_ok(g); + } else { + size_t bpp =3D + PIXMAN_FORMAT_BPP(pixman_image_get_format(res->image)) / 8; + size_t size =3D width * height * bpp; + + VhostUserGpuMsg *msg =3D g_malloc(VHOST_USER_GPU_HDR_SIZE + + sizeof(VhostUserGpuUpdate) + size); + msg->request =3D VHOST_USER_GPU_UPDATE; + msg->size =3D sizeof(VhostUserGpuUpdate) + size; + msg->payload.update.scanout_id =3D i; + msg->payload.update.x =3D extents->x1; + msg->payload.update.y =3D extents->y1; + msg->payload.update.width =3D width; + msg->payload.update.height =3D height; + pixman_image_t *i =3D + pixman_image_create_bits(pixman_image_get_format(res->imag= e), + msg->payload.update.width, + msg->payload.update.height, + (uint32_t *)msg->payload.update.d= ata, + 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 =3D 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 =3D container_of(dev, VuGpu, dev.parent); + VuVirtq *vq =3D vu_get_queue(dev, qidx); + struct virtio_gpu_ctrl_command *cmd =3D NULL; + size_t len; + + for (;;) { + cmd =3D vu_queue_pop(dev, vq, sizeof(struct virtio_gpu_ctrl_comman= d)); + if (!cmd) { + break; + } + cmd->vq =3D vq; + cmd->error =3D 0; + cmd->finished =3D false; + + len =3D iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, + 0, &cmd->cmd_hdr, sizeof(cmd->cmd_hdr)); + if (len !=3D 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 =3D virtio_gpu_find_resource(g, resource_id); + g_return_if_fail(res !=3D NULL); + g_return_if_fail(pixman_image_get_width(res->image) =3D=3D 64); + g_return_if_fail(pixman_image_get_height(res->image) =3D=3D 64); + g_return_if_fail( + PIXMAN_FORMAT_BPP(pixman_image_get_format(res->image)) =3D=3D 32); + + memcpy(data, pixman_image_get_data(res->image), 64 * 64 * sizeof(uint3= 2_t)); +} + +static void +vg_process_cursor_cmd(VuGpu *g, struct virtio_gpu_update_cursor *cursor) +{ + bool move =3D cursor->hdr.type !=3D VIRTIO_GPU_CMD_MOVE_CURSOR; + + g_debug("%s move:%d\n", G_STRFUNC, move); + + if (move) { + VhostUserGpuMsg msg =3D { + .request =3D cursor->resource_id ? + VHOST_USER_GPU_CURSOR_POS : VHOST_USER_GPU_CURSOR_POS_HIDE, + .size =3D sizeof(VhostUserGpuCursorPos), + .payload.cursor_pos =3D { + .scanout_id =3D cursor->pos.scanout_id, + .x =3D cursor->pos.x, + .y =3D cursor->pos.y, + } + }; + vg_send_msg(g, &msg, -1); + } else { + VhostUserGpuMsg msg =3D { + .request =3D VHOST_USER_GPU_CURSOR_UPDATE, + .size =3D sizeof(VhostUserGpuCursorUpdate), + .payload.cursor_update =3D { + .pos =3D { + .scanout_id =3D cursor->pos.scanout_id, + .x =3D cursor->pos.x, + .y =3D cursor->pos.y, + }, + .hot_x =3D cursor->hot_x, + .hot_y =3D 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 =3D container_of(dev, VuGpu, dev.parent); + VuVirtq *vq =3D vu_get_queue(dev, qidx); + VuVirtqElement *elem; + size_t len; + struct virtio_gpu_update_cursor cursor; + + for (;;) { + elem =3D 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 =3D iov_to_buf(elem->out_sg, elem->out_num, + 0, &cursor, sizeof(cursor)); + if (len !=3D 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 =3D 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 =3D { + .request =3D VHOST_USER_GPU_GET_PROTOCOL_FEATURES + }; + + vg_send_msg(g, &msg, -1); + if (vg_sock_fd_read(g->sock_fd, &u64, sizeof(u64)) < 0) { + vg_sock_fd_close(g); + return; + } + msg =3D (VhostUserGpuMsg) { + .request =3D VHOST_USER_GPU_SET_PROTOCOL_FEATURES, + .size =3D sizeof(uint64_t), + .payload.u64 =3D 0 + }; + vg_send_msg(g, &msg, -1); +} + +static int +vg_process_msg(VuDev *dev, VhostUserMsg *msg, int *do_reply) +{ + VuGpu *g =3D container_of(dev, VuGpu, dev.parent); + + switch (msg->request) { + case VHOST_USER_GPU_SET_SOCKET: { + g_return_val_if_fail(msg->fd_num =3D=3D 1, 1); + g_return_val_if_fail(g->sock_fd =3D=3D -1, 1); + g->sock_fd =3D msg->fds[0]; + set_protocol_features(g); + return 1; + } + case VHOST_USER_GPU_GET_NUM_CAPSETS: + g_return_val_if_fail(msg->fd_num =3D=3D 0, 1); + msg->payload.u64 =3D vg_virgl_get_num_capsets(); + msg->size =3D sizeof(msg->payload.u64); + *do_reply =3D true; + return 1; + default: + return 0; + } + + return 0; +} + +static uint64_t +vg_get_features(VuDev *dev) +{ + uint64_t features =3D 0; + + if (opt_virgl) { + features |=3D 1 << VIRTIO_GPU_F_VIRGL; + } + + return features; +} + +static void +vg_set_features(VuDev *dev, uint64_t features) +{ + VuGpu *g =3D container_of(dev, VuGpu, dev.parent); + bool virgl =3D 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 =3D true; + } + + g->virgl =3D virgl; +} + +static const VuDevIface vuiface =3D { + .set_features =3D vg_set_features, + .get_features =3D vg_get_features, + .queue_set_started =3D vg_queue_set_started, + .process_msg =3D vg_process_msg, +}; + +static void +vg_destroy(VuGpu *g) +{ + struct virtio_gpu_simple_resource *res, *tmp; + + vug_deinit(&g->dev); + + vg_sock_fd_close(g); + + 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 =3D socket(AF_UNIX, SOCK_STREAM, 0); + if (sock <=3D 0) { + perror("socket"); + return -1; + } + + un.sun_family =3D AF_UNIX; + snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + len =3D 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[] =3D { + { "pid", 'p', 0, G_OPTION_ARG_FILENAME, &opt_pid_path, + "PID path", "PATH" }, + { "fd", 'f', 0, G_OPTION_ARG_INT, &opt_fdnum, + "Use inherited fd socket", "FDNUM" }, + { "socket-path", 's', 0, G_OPTION_ARG_INT, &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 =3D NULL; + Error *err =3D NULL; + GMainLoop *loop =3D NULL; + int fd; + VuGpu g =3D { .sock_fd =3D -1, .drm_rnode_fd =3D -1 }; + + QTAILQ_INIT(&g.reslist); + QTAILQ_INIT(&g.fenceq); + + context =3D 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(EXIT_FAILURE); + } + g_option_context_free(context); + + if (opt_pid_path && !qemu_write_pidfile(opt_pid_path, &err)) { + g_printerr("%s\n", error_get_pretty(err)); + error_free(err); + exit(EXIT_FAILURE); + } + + g.drm_rnode_fd =3D qemu_drm_rendernode_open(opt_render_node); + if (opt_render_node && g.drm_rnode_fd =3D=3D -1) { + g_printerr("Failed to open DRM rendernode.\n"); + exit(EXIT_FAILURE); + } + + if (g.drm_rnode_fd >=3D 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 =3D unix_sock_new(opt_socket_path); + fd =3D accept(lsock, NULL, NULL); + close(lsock); + } else { + fd =3D opt_fdnum; + } + if (fd =3D=3D -1) { + g_printerr("Invalid socket"); + exit(EXIT_FAILURE); + } + + vug_init(&g.dev, fd, vg_panic, &vuiface); + + loop =3D g_main_loop_new(NULL, FALSE); + g_main_loop_run(loop); + g_main_loop_unref(loop); + + vg_destroy(&g); + if (g.drm_rnode_fd >=3D 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=C3=A9 Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * 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 =3D virgl_renderer_get_cursor_data(resource_id, &width, &height= ); + g_return_if_fail(cursor !=3D NULL); + g_return_if_fail(width =3D=3D 64); + g_return_if_fail(height =3D=3D 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 =3D c2d.resource_id; + args.target =3D 2; + args.format =3D c2d.format; + args.bind =3D (1 << 1); + args.width =3D c2d.width; + args.height =3D c2d.height; + args.depth =3D 1; + args.array_size =3D 1; + args.last_level =3D 0; + args.nr_samples =3D 0; + args.flags =3D 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 =3D c3d.resource_id; + args.target =3D c3d.target; + args.format =3D c3d.format; + args.bind =3D c3d.bind; + args.width =3D c3d.width; + args.height =3D c3d.height; + args.depth =3D c3d.depth; + args.array_size =3D c3d.array_size; + args.last_level =3D c3d.last_level; + args.nr_samples =3D c3d.nr_samples; + args.flags =3D 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 =3D=3D 0) { + resp.capset_id =3D 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 =3D=3D 1) { + resp.capset_id =3D 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 =3D 0; + resp.capset_max_size =3D 0; + } + resp.hdr.type =3D 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 =3D g_malloc0(sizeof(*resp) + max_size); + + resp->hdr.type =3D 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 =3D g_malloc(cs.size); + s =3D iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, + sizeof(cs), buf, cs.size); + if (s !=3D cs.size) { + g_critical("%s: size mismatch (%zd/%d)", __func__, s, cs.size); + cmd->error =3D 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 =3D t2d.r.x; + box.y =3D t2d.r.y; + box.z =3D 0; + box.w =3D t2d.r.width; + box.h =3D t2d.r.height; + box.d =3D 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 =3D vg_create_mapping_iov(g, &att_rb, cmd, &res_iovs); + if (ret !=3D 0) { + cmd->error =3D 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 =3D NULL; + int num_iovs =3D 0; + + VUGPU_FILL_CMD(detach_rb); + + virgl_renderer_resource_detach_iov(detach_rb.resource_id, + &res_iovs, + &num_iovs); + if (res_iovs =3D=3D NULL || num_iovs =3D=3D 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 >=3D VIRTIO_GPU_MAX_SCANOUTS) { + g_critical("%s: illegal scanout id specified %d", + __func__, ss.scanout_id); + cmd->error =3D VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + + memset(&info, 0, sizeof(info)); + + if (ss.resource_id && ss.r.width && ss.r.height) { + ret =3D virgl_renderer_resource_get_info(ss.resource_id, &info); + if (ret =3D=3D -1) { + g_critical("%s: illegal resource specified %d\n", + __func__, ss.resource_id); + cmd->error =3D VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + + int fd =3D -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 =3D VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID; + return; + } + assert(fd >=3D 0); + VhostUserGpuMsg msg =3D { + .request =3D VHOST_USER_GPU_DMABUF_SCANOUT, + .size =3D sizeof(VhostUserGpuDMABUFScanout), + .payload.dmabuf_scanout.scanout_id =3D ss.scanout_id, + .payload.dmabuf_scanout.x =3D ss.r.x, + .payload.dmabuf_scanout.y =3D ss.r.y, + .payload.dmabuf_scanout.width =3D ss.r.width, + .payload.dmabuf_scanout.height =3D ss.r.height, + .payload.dmabuf_scanout.fd_width =3D info.width, + .payload.dmabuf_scanout.fd_height =3D info.height, + .payload.dmabuf_scanout.fd_stride =3D info.stride, + .payload.dmabuf_scanout.fd_flags =3D info.flags, + .payload.dmabuf_scanout.fd_drm_fourcc =3D info.drm_fourcc + }; + vg_send_msg(g, &msg, fd); + close(fd); + } else { + VhostUserGpuMsg msg =3D { + .request =3D VHOST_USER_GPU_DMABUF_SCANOUT, + .size =3D sizeof(VhostUserGpuDMABUFScanout), + .payload.dmabuf_scanout.scanout_id =3D ss.scanout_id, + }; + g_debug("disable scanout"); + vg_send_msg(g, &msg, -1); + } + g->scanout[ss.scanout_id].resource_id =3D 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 =3D 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) { + if (g->scanout[i].resource_id !=3D rf.resource_id) { + continue; + } + VhostUserGpuMsg msg =3D { + .request =3D VHOST_USER_GPU_DMABUF_UPDATE, + .size =3D sizeof(VhostUserGpuUpdate), + .payload.update.scanout_id =3D i, + .payload.update.x =3D rf.r.x, + .payload.update.y =3D rf.r.y, + .payload.update.width =3D rf.r.width, + .payload.update.height =3D 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.resourc= e_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.resourc= e_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 =3D 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 =3D 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 >=3D 2 +static int +virgl_get_drm_fd(void *opaque) +{ + VuGpu *g =3D opaque; + + return g->drm_rnode_fd; +} +#endif + +static struct virgl_renderer_callbacks virgl_cbs =3D { +#if defined(VIRGL_RENDERER_CALLBACKS_VERSION) && \ + VIRGL_RENDERER_CALLBACKS_VERSION >=3D 2 + .get_drm_fd =3D virgl_get_drm_fd, + .version =3D 2, +#else + .version =3D 1, +#endif + .write_fence =3D 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 =3D=3D 1) { + g_warning("virgl will use the default rendernode"); + } + + ret =3D virgl_renderer_init(g, + VIRGL_RENDERER_USE_EGL | + VIRGL_RENDERER_THREAD_SYNC, + &virgl_cbs); + if (ret !=3D 0) { + return false; + } + + ret =3D virgl_renderer_get_poll_fd(); + if (ret !=3D -1) { + g->renderer_source =3D + vug_source_new(&g->dev, ret, G_IO_IN, vg_virgl_poll, g); + } + + return true; +} diff --git a/MAINTAINERS b/MAINTAINERS index 01e2b47c34..d340928bcd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1376,6 +1376,8 @@ M: Marc-Andr=C3=A9 Lureau M: Gerd Hoffmann S: Maintained F: docs/interop/vhost-user-gpu.rst +F: contrib/vhost-user-gpu +F: hw/display/vhost-user-* =20 Cirrus VGA M: Gerd Hoffmann diff --git a/Makefile b/Makefile index 0c61563d75..32a93d37c0 100644 --- a/Makefile +++ b/Makefile @@ -420,6 +420,7 @@ dummy :=3D $(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 \ @@ -720,6 +721,8 @@ vhost-user-blk$(EXESUF): $(vhost-user-blk-obj-y) libvho= st-user.a $(call LINK, $^) vhost-user-input$(EXESUF): $(vhost-user-input-obj-y) libvhost-user.a libqe= muutil.a $(call LINK, $^) +vhost-user-gpu$(EXESUF): $(vhost-user-gpu-obj-y) $(libvhost-user-obj-y) li= bqemuutil.a libqemustub.a + $(call LINK, $^) =20 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 :=3D $(LIBISCSI_LIBS) vhost-user-scsi-obj-y =3D contrib/vhost-user-scsi/ vhost-user-blk-obj-y =3D contrib/vhost-user-blk/ vhost-user-input-obj-y =3D contrib/vhost-user-input/ +vhost-user-gpu-obj-y =3D contrib/vhost-user-gpu/ =20 ###################################################################### trace-events-subdirs =3D diff --git a/configure b/configure index 211301f497..5727c433a5 100755 --- a/configure +++ b/configure @@ -3882,6 +3882,20 @@ libs_softmmu=3D"$libs_softmmu $fdt_libs" ########################################## # opengl probe (for sdl2, gtk, milkymist-tmu2) =20 +libdrm=3D"no" +if $pkg_config libdrm; then + libdrm_cflags=3D"$($pkg_config --cflags libdrm)" + libdrm_libs=3D"$($pkg_config --libs libdrm)" + libdrm=3D"yes" +fi + +libdrm_intel=3D"no" +if $pkg_config libdrm_intel; then + libdrm_intel_cflags=3D"$($pkg_config --cflags libdrm_intel)" + libdrm_intel_libs=3D"$($pkg_config --libs libdrm_intel)" + libdrm_intel=3D"yes" +fi + if test "$opengl" !=3D "no" ; then opengl_pkgs=3D"epoxy gbm" if $pkg_config $opengl_pkgs; then @@ -5637,6 +5651,9 @@ if test "$want_tools" =3D "yes" ; then if [ "$linux" =3D "yes" ] ; then tools=3D"vhost-user-input\$(EXESUF) $tools" fi + if [ "$linux" =3D "yes" -a "$virglrenderer" =3D "yes" -a "$libdrm" =3D "= yes" ] ; then + tools=3D"vhost-user-gpu\$(EXESUF) $tools" + fi fi if test "$softmmu" =3D yes ; then if test "$linux" =3D yes; then @@ -6507,6 +6524,18 @@ if test "$opengl" =3D "yes" ; then fi fi =20 +if test "$libdrm" =3D "yes" ; then + echo "CONFIG_LIBDRM=3Dy" >> $config_host_mak + echo "LIBDRM_LIBS=3D$libdrm_libs" >> $config_host_mak + echo "LIBDRM_CFLAGS=3D$libdrm_cflags" >> $config_host_mak +fi + +if test "$libdrm_intel" =3D "yes" ; then + echo "CONFIG_LIBDRM_INTEL=3Dy" >> $config_host_mak + echo "LIBDRM_INTEL_LIBS=3D$libdrm_intel_libs" >> $config_host_mak + echo "LIBDRM_INTEL_CFLAGS=3D$libdrm_intel_cflags" >> $config_host_mak +fi + if test "$malloc_trim" =3D "yes" ; then echo "CONFIG_MALLOC_TRIM=3Dy" >> $config_host_mak fi @@ -7331,6 +7360,9 @@ echo "QEMU_CFLAGS+=3D$cflags" >> $config_target_mak =20 done # for target in $targets =20 +echo "PIXMAN_CFLAGS=3D$pixman_cflags" >> $config_host_mak +echo "PIXMAN_LIBS=3D$pixman_libs" >> $config_host_mak + if test -n "$enabled_cross_compilers"; then echo echo "NOTE: cross-compilers enabled: $enabled_cross_compilers" 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 =3D main.o virgl.o drm.o + +main.o-cflags :=3D $(PIXMAN_CFLAGS) +main.o-libs :=3D $(PIXMAN_LIBS) + +virgl.o-cflags :=3D $(VIRGL_CFLAGS) +virgl.o-libs :=3D $(VIRGL_LIBS) + +drm.o-cflags :=3D $(LIBDRM_CFLAGS) $(LIBDRM_INTEL_CFLAGS) +drm.o-libs :=3D $(LIBDRM_LIBS) $(LIBDRM_INTEL_LIBS) --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488046255146.94246494955155; Fri, 13 Jul 2018 06:20:46 -0700 (PDT) Received: from localhost ([::1]:37284 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy02-000427-9R for importer@patchew.org; Fri, 13 Jul 2018 09:20:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41387) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxpv-0004SS-7S for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:16 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpt-0005IW-HV for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:14 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57152 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 1fdxps-0005FO-Oq for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:13 -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 56708C12A5 for ; Fri, 13 Jul 2018 13:10:12 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 03CF82156889; Fri, 13 Jul 2018 13:10:11 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:10 +0200 Message-Id: <20180713130916.4153-24-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.1]); Fri, 13 Jul 2018 13:10:12 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 13 Jul 2018 13:10: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:'' Content-Transfer-Encoding: quoted-printable 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 v4 23/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Marc-Andr=C3=A9 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 9780f755ef..c54c903a65 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -97,7 +97,6 @@ typedef struct VirtIOGPU { int enable; =20 int config_size; - DeviceState *qdev; =20 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 28602c1a35..30027f3384 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1219,7 +1219,6 @@ static void virtio_gpu_device_realize(DeviceState *qd= ev, Error **errp) QTAILQ_INIT(&g->fenceq); =20 g->enabled_output_bitmask =3D 1; - g->qdev =3D qdev; =20 for (i =3D 0; i < g->conf.max_outputs; i++) { g->scanout[i].con =3D --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488227822857.2111525105581; Fri, 13 Jul 2018 06:23:47 -0700 (PDT) Received: from localhost ([::1]:37304 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy2w-0006NA-7M for importer@patchew.org; Fri, 13 Jul 2018 09:23:42 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41427) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxq1-0004bh-Gs for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxpy-0005f0-9W for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:21 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40368 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 1fdxpx-0005bo-N7 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:18 -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 632FF72632 for ; Fri, 13 Jul 2018 13:10:17 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9F5BC23140; Fri, 13 Jul 2018 13:10:13 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:11 +0200 Message-Id: <20180713130916.4153-25-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:10:17 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Fri, 13 Jul 2018 13:10:17 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 24/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Marc-Andr=C3=A9 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 c54c903a65..4c68bc4559 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -96,8 +96,6 @@ typedef struct VirtIOGPU { =20 int enable; =20 - 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 30027f3384..7cfb25879a 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1189,10 +1189,9 @@ static void virtio_gpu_device_realize(DeviceState *q= dev, Error **errp) } } =20 - g->config_size =3D sizeof(struct virtio_gpu_config); g->virtio_config.num_scanouts =3D 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)); =20 g->req_state[0].width =3D g->conf.xres; g->req_state[0].height =3D g->conf.yres; --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488668673151.8770004090768; Fri, 13 Jul 2018 06:31:08 -0700 (PDT) Received: from localhost ([::1]:37361 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdyA7-0004W4-IE for importer@patchew.org; Fri, 13 Jul 2018 09:31:07 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41428) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxq1-0004bi-Gr for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxq0-0005nC-69 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:21 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:57170 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 1fdxpz-0005iO-8E for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:19 -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 EA1D5C12AC for ; Fri, 13 Jul 2018 13:10:18 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8AE752156889; Fri, 13 Jul 2018 13:10:18 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:12 +0200 Message-Id: <20180713130916.4153-26-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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.1]); Fri, 13 Jul 2018 13:10:18 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 13 Jul 2018 13:10:18 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 25/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" 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=C3=A9 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 4c68bc4559..763e1291f1 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -166,7 +166,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); =20 - cmd->waiting =3D 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) } } =20 -void virtio_gpu_gl_block(void *opaque, bool block) -{ - VirtIOGPU *g =3D opaque; - - if (block) { - g->renderer_blocked++; - } else { - g->renderer_blocked--; - } - assert(g->renderer_blocked >=3D 0); - - if (g->renderer_blocked =3D=3D 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 7cfb25879a..26a2592c4a 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -840,12 +840,15 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) while (!QTAILQ_EMPTY(&g->cmdq)) { cmd =3D QTAILQ_FIRST(&g->cmdq); =20 - /* process command */ - VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_c= md, - g, cmd); + cmd->waiting =3D g->renderer_blocked; if (cmd->waiting) { break; } + + /* process command */ + VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_c= md, + g, cmd); + QTAILQ_REMOVE(&g->cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->conf)) { g->stats.requests++; @@ -981,6 +984,22 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t i= dx, QemuUIInfo *info) return 0; } =20 +static void virtio_gpu_gl_block(void *opaque, bool block) +{ + VirtIOGPU *g =3D opaque; + + if (block) { + g->renderer_blocked++; + } else { + g->renderer_blocked--; + } + assert(g->renderer_blocked >=3D 0); + + if (g->renderer_blocked =3D=3D 0) { + virtio_gpu_process_cmdq(g); + } +} + const GraphicHwOps virtio_gpu_ops =3D { .invalidate =3D virtio_gpu_invalidate_display, .gfx_update =3D virtio_gpu_update_display, --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488965178173.53224578760273; Fri, 13 Jul 2018 06:36:05 -0700 (PDT) Received: from localhost ([::1]:37405 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdyEk-0007gF-HV for importer@patchew.org; Fri, 13 Jul 2018 09:35:54 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41479) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxq7-0004ez-0S for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxq5-00064b-HZ for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:26 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:51562 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 1fdxq5-00063N-9k for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:25 -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 EE019406C792 for ; Fri, 13 Jul 2018 13:10:24 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3B26C10FFE50; Fri, 13 Jul 2018 13:10:20 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:13 +0200 Message-Id: <20180713130916.4153-27-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:10:24 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 13 Jul 2018 13:10:24 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 26/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Let's check renderer_blocked instead directly. Signed-off-by: Marc-Andr=C3=A9 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 763e1291f1..6b07efc4f7 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -81,7 +81,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 26a2592c4a..b83982b0a3 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -840,8 +840,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) while (!QTAILQ_EMPTY(&g->cmdq)) { cmd =3D QTAILQ_FIRST(&g->cmdq); =20 - cmd->waiting =3D g->renderer_blocked; - if (cmd->waiting) { + if (g->renderer_blocked) { break; } =20 @@ -890,7 +889,6 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, = VirtQueue *vq) cmd->vq =3D vq; cmd->error =3D 0; cmd->finished =3D false; - cmd->waiting =3D false; QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next); cmd =3D virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); } --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531489261213668.2084194164133; Fri, 13 Jul 2018 06:41:01 -0700 (PDT) Received: from localhost ([::1]:37440 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdyJf-0003A4-J2 for importer@patchew.org; Fri, 13 Jul 2018 09:40:59 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41524) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxqC-0004kN-Qy for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxq7-00068q-TK for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:32 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:40380 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 1fdxq7-00067g-IK for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10: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 2C78B7DAC8 for ; Fri, 13 Jul 2018 13:10:27 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5BAF42156889; Fri, 13 Jul 2018 13:10:26 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:14 +0200 Message-Id: <20180713130916.4153-28-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:10:27 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Fri, 13 Jul 2018 13:10:27 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 27/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Add a base class that is common to virtio-gpu and vhost-user-gpu devices. The VirtIOGPUBase base class provides common functionalities necessary for both virtio-gpu and vhost-user-gpu: - common configuration (max-outputs, initial resolution, flags) - virtio device initialization, including queue setup - device pre-conditions checks (iommu) - migration blocker - virtio device callbacks - hooking up to qemu display subsystem - a few common helper functions to reset the device, retrieve display informations - a class callback to unblock the rendering (for GL updates) What is left to the virtio-gpu subdevice to take care of, in short, are all the virtio queues handling, command processing and migration. Signed-off-by: Marc-Andr=C3=A9 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 | 332 ++++++--------------------------- hw/display/virtio-vga.c | 15 +- hw/display/Makefile.objs | 2 +- 7 files changed, 447 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 6b07efc4f7..2edf47e9ab 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -22,6 +22,14 @@ =20 #include "standard-headers/linux/virtio_gpu.h" =20 +#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) @@ -58,7 +66,7 @@ struct virtio_gpu_requested_state { int x, y; }; =20 -enum virtio_gpu_conf_flags { +enum virtio_gpu_base_conf_flags { VIRTIO_GPU_FLAG_VIRGL_ENABLED =3D 1, VIRTIO_GPU_FLAG_STATS_ENABLED, }; @@ -68,8 +76,7 @@ enum virtio_gpu_conf_flags { #define virtio_gpu_stats_enabled(_cfg) \ (_cfg.flags & (1 << VIRTIO_GPU_FLAG_STATS_ENABLED)) =20 -struct virtio_gpu_conf { - uint64_t max_hostmem; +struct virtio_gpu_base_conf { uint32_t max_outputs; uint32_t flags; uint32_t xres; @@ -85,31 +92,53 @@ struct virtio_gpu_ctrl_command { QTAILQ_ENTRY(virtio_gpu_ctrl_command) next; }; =20 -typedef struct VirtIOGPU { +typedef struct VirtIOGPUBase { VirtIODevice parent_obj; =20 - 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; =20 - int enable; + QEMUBH *ctrl_bh; + QEMUBH *cursor_bh; =20 QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist; QTAILQ_HEAD(, virtio_gpu_ctrl_command) cmdq; QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq; =20 - 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; =20 - bool use_virgl_renderer; bool renderer_inited; - int renderer_blocked; QEMUTimer *fence_poll; QEMUTimer *print_stats; =20 @@ -120,8 +149,6 @@ typedef struct VirtIOGPU { uint32_t req_3d; uint32_t bytes_3d; } stats; - - Error *migration_blocker; } VirtIOGPU; =20 extern const GraphicHwOps virtio_gpu_ops; @@ -144,6 +171,16 @@ extern const GraphicHwOps virtio_gpu_ops; } \ } while (0) =20 +/* 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, @@ -167,4 +204,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; } =20 - dpy_gl_update(g->scanout[idx].con, x, y, width, height); + dpy_gl_update(g->parent_obj.scanout[idx].con, x, y, width, height); } =20 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= ); =20 - for (i =3D 0; i < g->conf.max_outputs; i++) { - if (g->scanout[i].resource_id !=3D rf.resource_id) { + for (i =3D 0; i < g->parent_obj.conf.max_outputs; i++) { + if (g->parent_obj.scanout[i].resource_id !=3D rf.resource_id) { continue; } virtio_gpu_rect_update(g, i, rf.r.x, rf.r.y, rf.r.width, rf.r.heig= ht); @@ -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); =20 - if (ss.scanout_id >=3D g->conf.max_outputs) { + if (ss.scanout_id >=3D g->parent_obj.conf.max_outputs) { qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %= d", __func__, ss.scanout_id); cmd->error =3D VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; return; } - g->enable =3D 1; + g->parent_obj.enable =3D 1; =20 memset(&info, 0, sizeof(info)); =20 @@ -173,20 +173,22 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g, cmd->error =3D 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 !=3D 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 =3D ss.resource_id; + g->parent_obj.scanout[ss.scanout_id].resource_id =3D ss.resource_id; } =20 static void virgl_cmd_submit_3d(VirtIOGPU *g, @@ -209,7 +211,7 @@ static void virgl_cmd_submit_3d(VirtIOGPU *g, goto out; } =20 - if (virtio_gpu_stats_enabled(g->conf)) { + if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->stats.req_3d++; g->stats.bytes_3d +=3D cs.size; } @@ -504,7 +506,7 @@ static void virgl_write_fence(void *opaque, uint32_t fe= nce) 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 =3D params->major_ver; qparams.minor_ver =3D params->minor_ver; =20 - ctx =3D dpy_gl_ctx_create(g->scanout[scanout_idx].con, &qparams); + ctx =3D dpy_gl_ctx_create(g->parent_obj.scanout[scanout_idx].con, &qpa= rams); return (virgl_renderer_gl_context)ctx; } =20 @@ -530,7 +532,7 @@ static void virgl_destroy_context(void *opaque, virgl_r= enderer_gl_context ctx) VirtIOGPU *g =3D opaque; QEMUGLContext qctx =3D (QEMUGLContext)ctx; =20 - dpy_gl_ctx_destroy(g->scanout[0].con, qctx); + dpy_gl_ctx_destroy(g->parent_obj.scanout[0].con, qctx); } =20 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 =3D opaque; QEMUGLContext qctx =3D (QEMUGLContext)ctx; =20 - 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); } =20 static struct virgl_renderer_callbacks virtio_gpu_3d_cbs =3D { @@ -591,11 +594,11 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g) int i; =20 /* virgl_renderer_reset() ??? */ - for (i =3D 0; i < g->conf.max_outputs; i++) { + for (i =3D 0; i < g->parent_obj.conf.max_outputs; i++) { if (i !=3D 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); } } =20 @@ -611,7 +614,7 @@ int virtio_gpu_virgl_init(VirtIOGPU *g) g->fence_poll =3D timer_new_ms(QEMU_CLOCK_VIRTUAL, virtio_gpu_fence_poll, g); =20 - if (virtio_gpu_stats_enabled(g->conf)) { + if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { g->print_stats =3D 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 late= r. + * 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 =3D 0; + g->use_virgl_renderer =3D false; + + for (i =3D 0; i < g->conf.max_outputs; i++) { + g->scanout[i].resource_id =3D 0; + g->scanout[i].width =3D 0; + g->scanout[i].height =3D 0; + g->scanout[i].x =3D 0; + g->scanout[i].y =3D 0; + g->scanout[i].ds =3D NULL; + } +} + +void +virtio_gpu_base_fill_display_info(VirtIOGPUBase *g, + struct virtio_gpu_resp_display_info *dpy= _info) +{ + int i; + + for (i =3D 0; i < g->conf.max_outputs; i++) { + if (g->enabled_output_bitmask & (1 << i)) { + dpy_info->pmodes[i].enabled =3D 1; + dpy_info->pmodes[i].r.width =3D cpu_to_le32(g->req_state[i].wi= dth); + dpy_info->pmodes[i].r.height =3D cpu_to_le32(g->req_state[i].h= eight); + } + } +} + +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 |=3D event_type; + virtio_notify_config(&g->parent_obj); +} + +static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) +{ + VirtIOGPUBase *g =3D opaque; + + if (idx >=3D g->conf.max_outputs) { + return -1; + } + + g->req_state[idx].x =3D info->xoff; + g->req_state[idx].y =3D info->yoff; + g->req_state[idx].width =3D info->width; + g->req_state[idx].height =3D info->height; + + if (info->width && info->height) { + g->enabled_output_bitmask |=3D (1 << idx); + } else { + g->enabled_output_bitmask &=3D ~(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 =3D opaque; + VirtIOGPUBaseClass *vgc =3D VIRTIO_GPU_BASE_GET_CLASS(g); + + if (block) { + g->renderer_blocked++; + } else { + g->renderer_blocked--; + } + assert(g->renderer_blocked >=3D 0); + if (g->renderer_blocked =3D=3D 0) { + vgc->gl_unblock(g); + } +} + +const GraphicHwOps virtio_gpu_ops =3D { + .invalidate =3D virtio_gpu_invalidate_display, + .gfx_update =3D virtio_gpu_update_display, + .text_update =3D virtio_gpu_text_update, + .ui_info =3D virtio_gpu_ui_info, + .gl_block =3D 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 =3D VIRTIO_DEVICE(qdev); + VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(qdev); + Error *local_err =3D 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_SCANOU= TS); + return false; + } + + g->use_virgl_renderer =3D 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 =3D 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 =3D num_capsets; + } else { + virtio_add_queue(vdev, 64, ctrl_cb); + virtio_add_queue(vdev, 16, cursor_cb); + } + + g->enabled_output_bitmask =3D 1; + + g->req_state[0].width =3D g->conf.xres; + g->req_state[0].height =3D g->conf.yres; + + for (i =3D 0; i < g->conf.max_outputs; i++) { + g->scanout[i].con =3D + 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 =3D 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 =3D 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 &=3D ~vgconfig.events_clear; + } +} + +static uint64_t +virtio_gpu_base_get_features(VirtIODevice *vdev, uint64_t features, + Error **errp) +{ + VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(vdev); + + if (virtio_gpu_virgl_enabled(g->conf)) { + features |=3D (1 << VIRTIO_GPU_F_VIRGL); + } + return features; +} + +static void +virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features) +{ + static const uint32_t virgl =3D (1 << VIRTIO_GPU_F_VIRGL); + VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(vdev); + + g->use_virgl_renderer =3D ((features & virgl) =3D=3D virgl); + trace_virtio_gpu_features(g->use_virgl_renderer); +} + +static void +virtio_gpu_base_device_unrealize(DeviceState *qdev, Error **errp) +{ + VirtIOGPUBase *g =3D 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 =3D DEVICE_CLASS(klass); + VirtioDeviceClass *vdc =3D VIRTIO_DEVICE_CLASS(klass); + + vdc->unrealize =3D virtio_gpu_base_device_unrealize; + vdc->get_features =3D virtio_gpu_base_get_features; + vdc->set_features =3D virtio_gpu_base_set_features; + vdc->get_config =3D virtio_gpu_base_get_config; + vdc->set_config =3D virtio_gpu_base_set_config; + + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + dc->hotpluggable =3D false; +} + +static const TypeInfo virtio_gpu_base_info =3D { + .name =3D TYPE_VIRTIO_GPU_BASE, + .parent =3D TYPE_VIRTIO_DEVICE, + .instance_size =3D sizeof(VirtIOGPUBase), + .class_size =3D sizeof(VirtIOGPUBaseClass), + .class_init =3D virtio_gpu_base_class_init, + .abstract =3D 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) !=3D 2= 4); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) !=3D 5= 6); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) !=3D 3= 2); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) !=3D 4= 0); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) !=3D 4= 8); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) !=3D 4= 8); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) !=3D 5= 6); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) !=3D 1= 6); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) !=3D 3= 2); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) !=3D 3= 2); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) !=3D 4= 08); + +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) !=3D 7= 2); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) !=3D 7= 2); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) !=3D 9= 6); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) !=3D 2= 4); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) !=3D 3= 2); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) !=3D 3= 2); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) !=3D 3= 2); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) !=3D 4= 0); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) !=3D 3= 2); +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) !=3D 2= 4); 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[] =3D { static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIOGPUPCI *vgpu =3D VIRTIO_GPU_PCI(vpci_dev); - VirtIOGPU *g =3D &vgpu->vdev; + VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vgpu->vdev); DeviceState *vdev =3D DEVICE(&vgpu->vdev); int i; Error *local_error =3D NULL; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index b83982b0a3..8609cb6eeb 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -21,9 +21,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" =20 #define VIRTIO_GPU_VM_VERSION 1 =20 @@ -36,7 +36,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__); \ @@ -104,10 +104,10 @@ static void update_cursor(VirtIOGPU *g, struct virtio= _gpu_update_cursor *cursor) struct virtio_gpu_scanout *s; bool move =3D cursor->hdr.type =3D=3D VIRTIO_GPU_CMD_MOVE_CURSOR; =20 - if (cursor->pos.scanout_id >=3D g->conf.max_outputs) { + if (cursor->pos.scanout_id >=3D g->parent_obj.conf.max_outputs) { return; } - s =3D &g->scanout[cursor->pos.scanout_id]; + s =3D &g->parent_obj.scanout[cursor->pos.scanout_id]; =20 trace_virtio_gpu_update_cursor(cursor->pos.scanout_id, cursor->pos.x, @@ -138,50 +138,6 @@ static void update_cursor(VirtIOGPU *g, struct virtio_= gpu_update_cursor *cursor) cursor->resource_id ? 1 : 0); } =20 -static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config) -{ - VirtIOGPU *g =3D VIRTIO_GPU(vdev); - memcpy(config, &g->virtio_config, sizeof(g->virtio_config)); -} - -static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *confi= g) -{ - VirtIOGPU *g =3D VIRTIO_GPU(vdev); - struct virtio_gpu_config vgconfig; - - memcpy(&vgconfig, config, sizeof(g->virtio_config)); - - if (vgconfig.events_clear) { - g->virtio_config.events_read &=3D ~vgconfig.events_clear; - } -} - -static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t featu= res, - Error **errp) -{ - VirtIOGPU *g =3D VIRTIO_GPU(vdev); - - if (virtio_gpu_virgl_enabled(g->conf)) { - features |=3D (1 << VIRTIO_GPU_F_VIRGL); - } - return features; -} - -static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features) -{ - static const uint32_t virgl =3D (1 << VIRTIO_GPU_F_VIRGL); - VirtIOGPU *g =3D VIRTIO_GPU(vdev); - - g->use_virgl_renderer =3D ((features & virgl) =3D=3D 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 |=3D event_type; - virtio_notify_config(&g->parent_obj); -} - static struct virtio_gpu_simple_resource * virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id) { @@ -230,21 +186,6 @@ void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g, virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp)); } =20 -static void -virtio_gpu_fill_display_info(VirtIOGPU *g, - struct virtio_gpu_resp_display_info *dpy_info) -{ - int i; - - for (i =3D 0; i < g->conf.max_outputs; i++) { - if (g->enabled_output_bitmask & (1 << i)) { - dpy_info->pmodes[i].enabled =3D 1; - dpy_info->pmodes[i].r.width =3D cpu_to_le32(g->req_state[i].wi= dth); - dpy_info->pmodes[i].r.height =3D cpu_to_le32(g->req_state[i].h= eight); - } - } -} - void virtio_gpu_get_display_info(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -253,7 +194,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 =3D 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)); } @@ -339,7 +280,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, } =20 res->hostmem =3D 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 =3D pixman_image_create_bits(pformat, c2d.width, c2d.height, @@ -361,7 +302,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, =20 static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id) { - struct virtio_gpu_scanout *scanout =3D &g->scanout[scanout_id]; + struct virtio_gpu_scanout *scanout =3D &g->parent_obj.scanout[scanout_= id]; struct virtio_gpu_simple_resource *res; DisplaySurface *ds =3D NULL; =20 @@ -393,7 +334,7 @@ static void virtio_gpu_resource_destroy(VirtIOGPU *g, int i; =20 if (res->scanout_bitmask) { - for (i =3D 0; i < g->conf.max_outputs; i++) { + for (i =3D 0; i < g->parent_obj.conf.max_outputs; i++) { if (res->scanout_bitmask & (1 << i)) { virtio_gpu_disable_scanout(g, i); } @@ -523,7 +464,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, =20 pixman_region_init_rect(&flush_region, rf.r.x, rf.r.y, rf.r.width, rf.r.height); - for (i =3D 0; i < g->conf.max_outputs; i++) { + for (i =3D 0; i < g->parent_obj.conf.max_outputs; i++) { struct virtio_gpu_scanout *scanout; pixman_region16_t region, finalregion; pixman_box16_t *extents; @@ -531,7 +472,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, if (!(res->scanout_bitmask & (1 << i))) { continue; } - scanout =3D &g->scanout[i]; + scanout =3D &g->parent_obj.scanout[i]; =20 pixman_region_init(&finalregion); pixman_region_init_rect(®ion, scanout->x, scanout->y, @@ -541,7 +482,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, pixman_region_translate(&finalregion, -scanout->x, -scanout->y); extents =3D 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); @@ -572,14 +513,14 @@ 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); =20 - if (ss.scanout_id >=3D g->conf.max_outputs) { + if (ss.scanout_id >=3D g->parent_obj.conf.max_outputs) { qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %= d", __func__, ss.scanout_id); cmd->error =3D VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; return; } =20 - g->enable =3D 1; + g->parent_obj.enable =3D 1; if (ss.resource_id =3D=3D 0) { virtio_gpu_disable_scanout(g, ss.scanout_id); return; @@ -608,7 +549,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, return; } =20 - scanout =3D &g->scanout[ss.scanout_id]; + scanout =3D &g->parent_obj.scanout[ss.scanout_id]; =20 format =3D pixman_image_get_format(res->image); bpp =3D DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8); @@ -631,7 +572,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); } =20 ores =3D virtio_gpu_find_resource(g, scanout->resource_id); @@ -840,7 +782,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) while (!QTAILQ_EMPTY(&g->cmdq)) { cmd =3D QTAILQ_FIRST(&g->cmdq); =20 - if (g->renderer_blocked) { + if (g->parent_obj.renderer_blocked) { break; } =20 @@ -849,14 +791,14 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) g, cmd); =20 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++; } =20 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 =3D g->inflight; } @@ -868,6 +810,11 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) } } =20 +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 =3D VIRTIO_GPU(vdev); @@ -878,7 +825,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, = VirtQueue *vq) } =20 #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 =3D true; } @@ -896,7 +843,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, = VirtQueue *vq) virtio_gpu_process_cmdq(g); =20 #ifdef CONFIG_VIRGL - if (g->use_virgl_renderer) { + if (g->parent_obj.use_virgl_renderer) { virtio_gpu_virgl_fence_poll(g); } #endif @@ -905,7 +852,7 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, = VirtQueue *vq) static void virtio_gpu_ctrl_bh(void *opaque) { VirtIOGPU *g =3D opaque; - virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq); + virtio_gpu_handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq); } =20 static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) @@ -943,71 +890,9 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vde= v, VirtQueue *vq) static void virtio_gpu_cursor_bh(void *opaque) { VirtIOGPU *g =3D 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 =3D opaque; - - if (idx >=3D g->conf.max_outputs) { - return -1; - } - - g->req_state[idx].x =3D info->xoff; - g->req_state[idx].y =3D info->yoff; - g->req_state[idx].width =3D info->width; - g->req_state[idx].height =3D info->height; - - if (info->width && info->height) { - g->enabled_output_bitmask |=3D (1 << idx); - } else { - g->enabled_output_bitmask &=3D ~(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); } =20 -static void virtio_gpu_gl_block(void *opaque, bool block) -{ - VirtIOGPU *g =3D opaque; - - if (block) { - g->renderer_blocked++; - } else { - g->renderer_blocked--; - } - assert(g->renderer_blocked >=3D 0); - - if (g->renderer_blocked =3D=3D 0) { - virtio_gpu_process_cmdq(g); - } -} - -const GraphicHwOps virtio_gpu_ops =3D { - .invalidate =3D virtio_gpu_invalidate_display, - .gfx_update =3D virtio_gpu_update_display, - .text_update =3D virtio_gpu_text_update, - .ui_info =3D virtio_gpu_ui_info, -#ifdef CONFIG_VIRGL - .gl_block =3D virtio_gpu_gl_block, -#endif -}; - static const VMStateDescription vmstate_virtio_gpu_scanout =3D { .name =3D "virtio-gpu-one-scanout", .version_id =3D 1, @@ -1030,10 +915,11 @@ static const VMStateDescription vmstate_virtio_gpu_s= canouts =3D { .name =3D "virtio-gpu-scanouts", .version_id =3D 1, .fields =3D (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() @@ -1143,8 +1029,8 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque,= size_t size, =20 /* load & apply scanout state */ vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1); - for (i =3D 0; i < g->conf.max_outputs; i++) { - scanout =3D &g->scanout[i]; + for (i =3D 0; i < g->parent_obj.conf.max_outputs; i++) { + scanout =3D &g->parent_obj.scanout[i]; if (!scanout->resource_id) { continue; } @@ -1173,117 +1059,54 @@ static void virtio_gpu_device_realize(DeviceState = *qdev, Error **errp) VirtIODevice *vdev =3D VIRTIO_DEVICE(qdev); VirtIOGPU *g =3D VIRTIO_GPU(qdev); bool have_virgl; - Error *local_err =3D NULL; - int i; + int num_capsets =3D 0; =20 - 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_SCANOU= TS); - return; - } - - g->use_virgl_renderer =3D false; #if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN) have_virgl =3D false; #else have_virgl =3D display_opengl; #endif if (!have_virgl) { - g->conf.flags &=3D ~(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 &=3D ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED= ); } =20 - g->virtio_config.num_scanouts =3D 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 =3D g->conf.xres; - g->req_state[0].height =3D g->conf.yres; - - if (virtio_gpu_virgl_enabled(g->conf)) { - /* use larger control queue in 3d mode */ - g->ctrl_vq =3D virtio_add_queue(vdev, 256, virtio_gpu_handle_ctr= l_cb); - g->cursor_vq =3D virtio_add_queue(vdev, 16, virtio_gpu_handle_curs= or_cb); - #if defined(CONFIG_VIRGL) - g->virtio_config.num_capsets =3D virtio_gpu_virgl_get_num_capsets(= g); -#else - g->virtio_config.num_capsets =3D 0; + num_capsets =3D virtio_gpu_virgl_get_num_capsets(g); #endif - } else { - g->ctrl_vq =3D virtio_add_queue(vdev, 64, virtio_gpu_handle_ctrl= _cb); - g->cursor_vq =3D virtio_add_queue(vdev, 16, virtio_gpu_handle_curs= or_cb); + + if (!virtio_gpu_base_device_realize(qdev, + num_capsets, + virtio_gpu_handle_ctrl_cb, + virtio_gpu_handle_cursor_cb, + errp)) { + return; } =20 + g->ctrl_vq =3D virtio_get_queue(vdev, 0); + g->cursor_vq =3D virtio_get_queue(vdev, 1); g->ctrl_bh =3D qemu_bh_new(virtio_gpu_ctrl_bh, g); g->cursor_bh =3D qemu_bh_new(virtio_gpu_cursor_bh, g); QTAILQ_INIT(&g->reslist); QTAILQ_INIT(&g->cmdq); QTAILQ_INIT(&g->fenceq); - - g->enabled_output_bitmask =3D 1; - - for (i =3D 0; i < g->conf.max_outputs; i++) { - g->scanout[i].con =3D - 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 =3D 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) -{ } =20 static void virtio_gpu_reset(VirtIODevice *vdev) { VirtIOGPU *g =3D VIRTIO_GPU(vdev); struct virtio_gpu_simple_resource *res, *tmp; - int i; =20 - g->enable =3D 0; +#ifdef CONFIG_VIRGL + if (g->parent_obj.use_virgl_renderer) { + virtio_gpu_virgl_reset(g); + } +#endif =20 QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { virtio_gpu_resource_destroy(g, res); } - for (i =3D 0; i < g->conf.max_outputs; i++) { - g->scanout[i].resource_id =3D 0; - g->scanout[i].width =3D 0; - g->scanout[i].height =3D 0; - g->scanout[i].x =3D 0; - g->scanout[i].y =3D 0; - g->scanout[i].ds =3D NULL; - } =20 -#ifdef CONFIG_VIRGL - if (g->use_virgl_renderer) { - virtio_gpu_virgl_reset(g); - g->use_virgl_renderer =3D 0; - } -#endif + virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev)); } =20 /* @@ -1314,16 +1137,15 @@ static const VMStateDescription vmstate_virtio_gpu = =3D { }; =20 static Property virtio_gpu_properties[] =3D { - DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1), - DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf.max_hostmem, 256 * MiB= ), + VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf), + DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem, + 256 * MiB), #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(), }; =20 @@ -1331,27 +1153,20 @@ static void virtio_gpu_class_init(ObjectClass *klas= s, void *data) { DeviceClass *dc =3D DEVICE_CLASS(klass); VirtioDeviceClass *vdc =3D VIRTIO_DEVICE_CLASS(klass); + VirtIOGPUBaseClass *vgc =3D VIRTIO_GPU_BASE_CLASS(klass); =20 + vgc->gl_unblock =3D virtio_gpu_gl_unblock; vdc->realize =3D virtio_gpu_device_realize; - vdc->unrealize =3D virtio_gpu_device_unrealize; - vdc->get_config =3D virtio_gpu_get_config; - vdc->set_config =3D virtio_gpu_set_config; - vdc->get_features =3D virtio_gpu_get_features; - vdc->set_features =3D virtio_gpu_set_features; - vdc->reset =3D virtio_gpu_reset; =20 - set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); - dc->props =3D virtio_gpu_properties; dc->vmsd =3D &vmstate_virtio_gpu; - dc->hotpluggable =3D false; + dc->props =3D virtio_gpu_properties; } =20 static const TypeInfo virtio_gpu_info =3D { .name =3D TYPE_VIRTIO_GPU, - .parent =3D TYPE_VIRTIO_DEVICE, + .parent =3D TYPE_VIRTIO_GPU_BASE, .instance_size =3D sizeof(VirtIOGPU), - .instance_init =3D virtio_gpu_instance_init, .class_init =3D virtio_gpu_class_init, }; =20 @@ -1361,26 +1176,3 @@ static void virtio_register_types(void) } =20 type_init(virtio_register_types) - -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr) !=3D 2= 4); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor) !=3D 5= 6); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref) !=3D 3= 2); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d) !=3D 4= 0); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout) !=3D 4= 8); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush) !=3D 4= 8); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d) !=3D 5= 6); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry) !=3D 1= 6); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) !=3D 3= 2); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) !=3D 3= 2); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info) !=3D 4= 08); - -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_host_3d) !=3D 7= 2); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_3d) !=3D 7= 2); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_create) !=3D 9= 6); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_destroy) !=3D 2= 4); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctx_resource) !=3D 3= 2); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_cmd_submit) !=3D 3= 2); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset_info) !=3D 3= 2); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset_info) !=3D 4= 0); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_get_capset) !=3D 3= 2); -QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_capset) !=3D 2= 4); diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 8d3d9e14a7..00939b7e0c 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 =3D opaque; + VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); =20 - 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 =3D opaque; + VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); =20 - 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 =3D opaque; + VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); =20 - 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 =3D { static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIOVGA *vvga =3D VIRTIO_VGA(vpci_dev); - VirtIOGPU *g =3D &vvga->vdev; + VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); VGACommonState *vga =3D &vvga->vga; Error *err =3D 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 =3D VIRTIO_VGA(dev); - vvga->vdev.enable =3D 0; + VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); + + g->enable =3D 0; =20 vga_dirty_log_start(&vvga->vga); } diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index fb8408c6d0..5e60015b77 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -39,7 +39,7 @@ obj-$(CONFIG_VGA) +=3D vga.o =20 common-obj-$(CONFIG_QXL) +=3D qxl.o qxl-logger.o qxl-render.o =20 -obj-$(CONFIG_VIRTIO_GPU) +=3D virtio-gpu.o virtio-gpu-3d.o +obj-$(CONFIG_VIRTIO_GPU) +=3D virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d= .o obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) +=3D virtio-gpu= -pci.o obj-$(CONFIG_VIRTIO_VGA) +=3D virtio-vga.o virtio-gpu.o-cflags :=3D $(VIRGL_CFLAGS) --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531489151968162.0924487796566; Fri, 13 Jul 2018 06:39:11 -0700 (PDT) Received: from localhost ([::1]:37424 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdyHu-0001bK-A1 for importer@patchew.org; Fri, 13 Jul 2018 09:39:10 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41512) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxqB-0004jN-Ui for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxq9-0006BO-Pk for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:31 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:50156 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 1fdxq9-0006AV-G7 for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:29 -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 EA71981A7CFF for ; Fri, 13 Jul 2018 13:10:28 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5FE942026D6B; Fri, 13 Jul 2018 13:10:28 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:15 +0200 Message-Id: <20180713130916.4153-29-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:10:28 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 13 Jul 2018 13:10:28 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 28/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Add base classes that are common to vhost-user-gpu-pci and vhost-user-vga. Signed-off-by: Marc-Andr=C3=A9 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; }; =20 + /* - * 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) =20 -struct VirtIOGPUPCI { +typedef struct VirtIOGPUPCIBase { VirtIOPCIProxy parent_obj; - VirtIOGPU vdev; -}; + + VirtIOGPUBase *vgpu; +} VirtIOGPUPCIBase; =20 #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" =20 -static Property virtio_gpu_pci_properties[] =3D { +static Property virtio_gpu_pci_base_properties[] =3D { DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), DEFINE_PROP_END_OF_LIST(), }; =20 -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 =3D VIRTIO_GPU_PCI(vpci_dev); - VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vgpu->vdev); - DeviceState *vdev =3D DEVICE(&vgpu->vdev); + VirtIOGPUPCIBase *vgpu =3D VIRTIO_GPU_PCI_BASE(vpci_dev); + VirtIOGPUBase *g =3D vgpu->vgpu; + DeviceState *vdev =3D DEVICE(g); int i; Error *local_error =3D NULL; =20 @@ -48,37 +48,56 @@ static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci= _dev, Error **errp) } } =20 -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 =3D DEVICE_CLASS(klass); VirtioPCIClass *k =3D VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k =3D PCI_DEVICE_CLASS(klass); =20 set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); - dc->props =3D virtio_gpu_pci_properties; + dc->props =3D virtio_gpu_pci_base_properties; dc->hotpluggable =3D false; - k->realize =3D virtio_gpu_pci_realize; + k->realize =3D virtio_gpu_pci_base_realize; pcidev_k->class_id =3D PCI_CLASS_DISPLAY_OTHER; } =20 +static const TypeInfo virtio_gpu_pci_base_info =3D { + .name =3D TYPE_VIRTIO_GPU_PCI_BASE, + .parent =3D TYPE_VIRTIO_PCI, + .instance_size =3D sizeof(VirtIOGPUPCIBase), + .class_init =3D virtio_gpu_pci_base_class_init, + .abstract =3D 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 =3D VIRTIO_GPU_PCI(obj); =20 virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU); + VIRTIO_GPU_PCI_BASE(obj)->vgpu =3D VIRTIO_GPU_BASE(&dev->vdev); } =20 static const TypeInfo virtio_gpu_pci_info =3D { .name =3D TYPE_VIRTIO_GPU_PCI, - .parent =3D TYPE_VIRTIO_PCI, + .parent =3D TYPE_VIRTIO_GPU_PCI_BASE, .instance_size =3D sizeof(VirtIOGPUPCI), .instance_init =3D virtio_gpu_initfn, - .class_init =3D virtio_gpu_pci_class_init, }; =20 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 00939b7e0c..57b7b65423 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" =20 -/* - * 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 =3D opaque; - VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga =3D opaque; + VirtIOGPUBase *g =3D vvga->vgpu; =20 if (g->enable) { - virtio_gpu_ops.invalidate(&vvga->vdev); + virtio_gpu_ops.invalidate(g); } else { vvga->vga.hw_ops->invalidate(&vvga->vga); } } =20 -static void virtio_vga_update_display(void *opaque) +static void virtio_vga_base_update_display(void *opaque) { - VirtIOVGA *vvga =3D opaque; - VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga =3D opaque; + VirtIOGPUBase *g =3D vvga->vgpu; =20 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); } } =20 -static void virtio_vga_text_update(void *opaque, console_ch_t *chardata) +static void virtio_vga_base_text_update(void *opaque, console_ch_t *charda= ta) { - VirtIOVGA *vvga =3D opaque; - VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga =3D opaque; + VirtIOGPUBase *g =3D vvga->vgpu; =20 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, consol= e_ch_t *chardata) } } =20 -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 =3D opaque; + VirtIOVGABase *vvga =3D opaque; + VirtIOGPUBase *g =3D vvga->vgpu; =20 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; } =20 -static void virtio_vga_gl_block(void *opaque, bool block) +static void virtio_vga_base_gl_block(void *opaque, bool block) { - VirtIOVGA *vvga =3D opaque; + VirtIOVGABase *vvga =3D opaque; + VirtIOGPUBase *g =3D vvga->vgpu; =20 if (virtio_gpu_ops.gl_block) { - virtio_gpu_ops.gl_block(&vvga->vdev, block); + virtio_gpu_ops.gl_block(g, block); } } =20 -static const GraphicHwOps virtio_vga_ops =3D { - .invalidate =3D virtio_vga_invalidate_display, - .gfx_update =3D virtio_vga_update_display, - .text_update =3D virtio_vga_text_update, - .ui_info =3D virtio_vga_ui_info, - .gl_block =3D virtio_vga_gl_block, +static const GraphicHwOps virtio_vga_base_ops =3D { + .invalidate =3D virtio_vga_base_invalidate_display, + .gfx_update =3D virtio_vga_base_update_display, + .text_update =3D virtio_vga_base_text_update, + .ui_info =3D virtio_vga_base_ui_info, + .gl_block =3D virtio_vga_base_gl_block, }; =20 -static const VMStateDescription vmstate_virtio_vga =3D { +static const VMStateDescription vmstate_virtio_vga_base =3D { .name =3D "virtio-vga", .version_id =3D 2, .minimum_version_id =3D 2, .fields =3D (VMStateField[]) { /* no pci stuff here, saving the virtio device will handle that */ - VMSTATE_STRUCT(vga, VirtIOVGA, 0, vmstate_vga_common, VGACommonSta= te), + VMSTATE_STRUCT(vga, VirtIOVGABase, 0, + vmstate_vga_common, VGACommonState), VMSTATE_END_OF_LIST() } }; =20 /* 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 =3D VIRTIO_VGA(vpci_dev); - VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga =3D VIRTIO_VGA_BASE(vpci_dev); + VirtIOGPUBase *g =3D vvga->vgpu; VGACommonState *vga =3D &vvga->vga; Error *err =3D NULL; uint32_t offset; @@ -159,7 +147,7 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev= , Error **errp) vvga->vga_mrs, true); =20 vga->con =3D 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); =20 for (i =3D 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_d= ev, Error **errp) } } =20 -static void virtio_vga_reset(DeviceState *dev) +static void virtio_vga_base_reset(DeviceState *dev) { - VirtIOVGA *vvga =3D VIRTIO_VGA(dev); - VirtIOGPUBase *g =3D VIRTIO_GPU_BASE(&vvga->vdev); + VirtIOVGABase *vvga =3D VIRTIO_VGA_BASE(dev); + VirtIOGPUBase *g =3D vvga->vgpu; =20 g->enable =3D 0; =20 vga_dirty_log_start(&vvga->vga); } =20 -static Property virtio_vga_properties[] =3D { +static Property virtio_vga_base_properties[] =3D { DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), DEFINE_PROP_END_OF_LIST(), }; =20 -static void virtio_vga_class_init(ObjectClass *klass, void *data) +static void virtio_vga_base_class_init(ObjectClass *klass, void *data) { DeviceClass *dc =3D DEVICE_CLASS(klass); VirtioPCIClass *k =3D VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k =3D PCI_DEVICE_CLASS(klass); =20 set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); - dc->props =3D virtio_vga_properties; - dc->reset =3D virtio_vga_reset; - dc->vmsd =3D &vmstate_virtio_vga; + dc->props =3D virtio_vga_base_properties; + dc->reset =3D virtio_vga_base_reset; + dc->vmsd =3D &vmstate_virtio_vga_base; dc->hotpluggable =3D false; =20 - k->realize =3D virtio_vga_realize; + k->realize =3D virtio_vga_base_realize; pcidev_k->romfile =3D "vgabios-virtio.bin"; pcidev_k->class_id =3D PCI_CLASS_DISPLAY_VGA; } =20 +static TypeInfo virtio_vga_base_info =3D { + .name =3D TYPE_VIRTIO_VGA_BASE, + .parent =3D TYPE_VIRTIO_PCI, + .instance_size =3D sizeof(struct VirtIOVGABase), + .class_init =3D virtio_vga_base_class_init, + .abstract =3D 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 =3D VIRTIO_VGA(obj); =20 virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU); + VIRTIO_VGA_BASE(dev)->vgpu =3D VIRTIO_GPU_BASE(&dev->vdev); } =20 static TypeInfo virtio_vga_info =3D { .name =3D TYPE_VIRTIO_VGA, - .parent =3D TYPE_VIRTIO_PCI, + .parent =3D TYPE_VIRTIO_VGA_BASE, .instance_size =3D sizeof(struct VirtIOVGA), .instance_init =3D virtio_vga_inst_initfn, - .class_init =3D virtio_vga_class_init, }; =20 static void virtio_vga_register_types(void) { + type_register_static(&virtio_vga_base_info); type_register_static(&virtio_vga_info); } =20 diff --git a/MAINTAINERS b/MAINTAINERS index d340928bcd..7b6a18edd4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1368,7 +1368,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 =20 vhost-user-gpu --=20 2.18.0.129.ge3331758f1 From nobody Tue Nov 4 21:28:33 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1531488639178969.8082364485674; Fri, 13 Jul 2018 06:30:39 -0700 (PDT) Received: from localhost ([::1]:37355 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdy9a-00041F-N5 for importer@patchew.org; Fri, 13 Jul 2018 09:30:34 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41539) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fdxqE-0004m0-Gh for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fdxqB-0006Ho-FQ for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:34 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:51566 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 1fdxqB-0006Fp-8M for qemu-devel@nongnu.org; Fri, 13 Jul 2018 09:10:31 -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 E74B64075E5B for ; Fri, 13 Jul 2018 13:10:30 +0000 (UTC) Received: from localhost (unknown [10.36.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 544222156889; Fri, 13 Jul 2018 13:10:30 +0000 (UTC) From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= To: qemu-devel@nongnu.org Date: Fri, 13 Jul 2018 15:09:16 +0200 Message-Id: <20180713130916.4153-30-marcandre.lureau@redhat.com> In-Reply-To: <20180713130916.4153-1-marcandre.lureau@redhat.com> References: <20180713130916.4153-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]); Fri, 13 Jul 2018 13:10:30 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 13 Jul 2018 13:10:30 +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:'' Content-Transfer-Encoding: quoted-printable 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 v4 29/29] 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: airlied@redhat.com, kraxel@redhat.com, =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" 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=3Dvug,cmd=3D"./vhost-user-gpu" -device vhost-user-vga,vhost-user=3Dvug Signed-off-by: Marc-Andr=C3=A9 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 | 524 ++++++++++++++++++++++++++++++++ hw/display/vhost-user-vga.c | 52 ++++ vl.c | 1 + hw/display/Makefile.objs | 3 + 7 files changed, 645 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; =20 diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 2edf47e9ab..83e9ee2eaa 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" =20 #include "standard-headers/linux/virtio_gpu.h" =20 @@ -34,6 +35,8 @@ #define VIRTIO_GPU(obj) \ OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU) =20 +#define TYPE_VHOST_USER_GPU "vhost-user-gpu" + #define VIRTIO_ID_GPU 16 =20 struct virtio_gpu_simple_resource { @@ -151,6 +154,16 @@ typedef struct VirtIOGPU { } stats; } VirtIOGPU; =20 +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; =20 /* to share between PCI and VGA */ diff --git a/hw/display/vhost-user-gpu-pci.c b/hw/display/vhost-user-gpu-pc= i.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 late= r. + * 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 =3D 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 =3D 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 =3D { + .name =3D TYPE_VHOST_USER_GPU_PCI, + .parent =3D TYPE_VIRTIO_GPU_PCI_BASE, + .instance_size =3D sizeof(VhostUserGPUPCI), + .instance_init =3D 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..3427c151e7 --- /dev/null +++ b/hw/display/vhost-user-gpu.c @@ -0,0 +1,524 @@ +/* + * vhost-user GPU Device + * + * Copyright Red Hat, Inc. 2018 + * + * Authors: + * Marc-Andr=C3=A9 Lureau + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * 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" +#include "migration/blocker.h" + +#define VHOST_USER_GPU(obj) \ + OBJECT_CHECK(VhostUserGPU, (obj), TYPE_VHOST_USER_GPU) + +typedef enum VhostUserGpuRequest { + VHOST_USER_GPU_NONE =3D 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 =3D &msg->payload.cursor_pos; + struct virtio_gpu_scanout *s; + + if (pos->scanout_id >=3D g->parent_obj.conf.max_outputs) { + return; + } + s =3D &g->parent_obj.scanout[pos->scanout_id]; + + if (msg->request =3D=3D VHOST_USER_GPU_CURSOR_UPDATE) { + VhostUserGpuCursorUpdate *up =3D &msg->payload.cursor_update; + if (!s->current_cursor) { + s->current_cursor =3D cursor_alloc(64, 64); + } + + s->current_cursor->hot_x =3D up->hot_x; + s->current_cursor->hot_y =3D 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 !=3D 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 =3D NULL; + struct virtio_gpu_scanout *s; + + switch (msg->request) { + case VHOST_USER_GPU_GET_PROTOCOL_FEATURES: { + uint64_t u64 =3D 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 =3D { 0, }; + display_info.hdr.type =3D VIRTIO_GPU_RESP_OK_DISPLAY_INFO; + virtio_gpu_base_fill_display_info(VIRTIO_GPU_BASE(g), &display_inf= o); + qemu_chr_fe_write(&g->vhost_chr, + (uint8_t *)&display_info, sizeof(display_info)); + break; + } + case VHOST_USER_GPU_SCANOUT: { + VhostUserGpuScanout *m =3D &msg->payload.scanout; + + if (m->scanout_id >=3D g->parent_obj.conf.max_outputs) { + return; + } + + g->parent_obj.enable =3D 1; + s =3D &g->parent_obj.scanout[m->scanout_id]; + con =3D s->con; + + if (m->scanout_id =3D=3D 0 && m->width =3D=3D 0) { + s->ds =3D qemu_create_message_surface(640, 480, + "Guest disabled display."); + } else { + s->ds =3D 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 =3D &msg->payload.dmabuf_scanout; + int fd =3D qemu_chr_fe_get_msgfd(&g->vhost_chr); + QemuDmaBuf *dmabuf; + + if (m->scanout_id >=3D g->parent_obj.conf.max_outputs) { + if (fd >=3D 0) { + close(fd); + } + break; + } + + g->parent_obj.enable =3D 1; + con =3D g->parent_obj.scanout[m->scanout_id].con; + dmabuf =3D &g->dmabuf[m->scanout_id]; + if (dmabuf->fd >=3D 0) { + close(dmabuf->fd); + dmabuf->fd =3D -1; + } + dpy_gl_release_dmabuf(con, dmabuf); + if (fd =3D=3D -1) { + dpy_gl_scanout_disable(con); + break; + } + *dmabuf =3D (QemuDmaBuf) { + .fd =3D fd, + .width =3D m->fd_width, + .height =3D m->fd_height, + .stride =3D m->fd_stride, + .fourcc =3D m->fd_drm_fourcc, + .y0_top =3D 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 =3D &msg->payload.update; + + if (m->scanout_id >=3D 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 =3D g->parent_obj.scanout[m->scanout_id].con; + dpy_gl_update(con, m->x, m->y, m->width, m->height); + g->backend_blocked =3D true; + break; + } + case VHOST_USER_GPU_UPDATE: { + VhostUserGpuUpdate *m =3D &msg->payload.update; + + if (m->scanout_id >=3D g->parent_obj.conf.max_outputs) { + break; + } + s =3D &g->parent_obj.scanout[m->scanout_id]; + con =3D s->con; + pixman_image_t *image =3D + 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 =3D opaque; + VhostUserGpuMsg *msg =3D NULL; + VhostUserGpuRequest request; + uint32_t size; + int r; + + r =3D qemu_chr_fe_read_all(&g->vhost_chr, + (uint8_t *)&request, sizeof(uint32_t)); + if (r !=3D sizeof(uint32_t)) { + error_report("failed to read msg header: %d, %d", r, errno); + goto end; + } + + r =3D qemu_chr_fe_read_all(&g->vhost_chr, + (uint8_t *)&size, sizeof(uint32_t)); + if (r !=3D sizeof(uint32_t)) { + error_report("failed to read msg size"); + goto end; + } + + msg =3D g_malloc(VHOST_USER_GPU_HDR_SIZE + size); + g_return_if_fail(msg !=3D NULL); + + r =3D qemu_chr_fe_read_all(&g->vhost_chr, + (uint8_t *)&msg->payload, size); + if (r !=3D size) { + error_report("failed to read msg payload %d !=3D %d", r, size); + goto end; + } + + msg->request =3D request; + msg->size =3D size; + + if (request =3D=3D VHOST_USER_GPU_CURSOR_UPDATE || + request =3D=3D VHOST_USER_GPU_CURSOR_POS || + request =3D=3D 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 =3D VHOST_USER_GPU(b); + + if (g->backend_blocked) { + vhost_user_gpu_unblock(VHOST_USER_GPU(g)); + g->backend_blocked =3D false; + } + + vhost_user_gpu_update_blocked(VHOST_USER_GPU(g), false); +} + +static bool +vhost_user_gpu_do_set_socket(VhostUserGPU *g, Error **errp) +{ + Chardev *chr; + int sv[2]; + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) =3D=3D -1) { + error_setg_errno(errp, errno, "socketpair() failed"); + return false; + } + + chr =3D CHARDEV(object_new(TYPE_CHARDEV_SOCKET)); + if (!chr || qemu_chr_add_client(chr, sv[0]) =3D=3D -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"); + qemu_chr_fe_deinit(&g->vhost_chr, false); + goto err; + } + + g->vhost_gpu_fd =3D sv[0]; + vhost_user_gpu_update_blocked(g, false); + close(sv[1]); + return true; + +err: + close(sv[0]); + close(sv[1]); + if (chr) { + object_unref(OBJECT(chr)); + } + return false; +} + +static void +vhost_user_gpu_set_status(VirtIODevice *vdev, uint8_t val) +{ + VhostUserGPU *g =3D VHOST_USER_GPU(vdev); + Error *err =3D NULL; + + if (val & VIRTIO_CONFIG_S_DRIVER_OK && vdev->vm_running) { + if (!vhost_user_gpu_do_set_socket(g, &err)) { + error_report_err(err); + return; + } + vhost_user_backend_start(g->vhost); + } else { + /* unblock any wait and stop processing */ + if (g->vhost_gpu_fd !=3D -1) { + vhost_user_gpu_update_blocked(g, true); + qemu_chr_fe_deinit(&g->vhost_chr, true); + g->vhost_gpu_fd =3D -1; + } + vhost_user_backend_stop(g->vhost); + } +} + +static bool +vhost_user_gpu_guest_notifier_pending(VirtIODevice *vdev, int idx) +{ + VhostUserGPU *g =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 =3D VHOST_USER_GPU(qdev); + VirtIODevice *vdev =3D VIRTIO_DEVICE(g); + 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 |=3D 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, err= p)) { + return; + } + + if (!g->parent_obj.migration_blocker) { + error_setg(&g->parent_obj.migration_blocker, + "vhost-user-gpu is not yet migratable"); + if (migrate_add_blocker(g->parent_obj.migration_blocker, errp) < 0= ) { + return; + } + } + + g->vhost_gpu_fd =3D -1; +} + +static Property vhost_user_gpu_properties[] =3D { + 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 =3D DEVICE_CLASS(klass); + VirtioDeviceClass *vdc =3D VIRTIO_DEVICE_CLASS(klass); + VirtIOGPUBaseClass *vgc =3D VIRTIO_GPU_BASE_CLASS(klass); + + vgc->gl_unblock =3D vhost_user_gpu_gl_unblock; + + vdc->realize =3D vhost_user_gpu_device_realize; + vdc->reset =3D vhost_user_gpu_reset; + vdc->set_status =3D vhost_user_gpu_set_status; + vdc->guest_notifier_mask =3D vhost_user_gpu_guest_notifier_mask; + vdc->guest_notifier_pending =3D vhost_user_gpu_guest_notifier_pending; + vdc->reset =3D vhost_user_gpu_reset; + + dc->props =3D vhost_user_gpu_properties; +} + +static const TypeInfo vhost_user_gpu_info =3D { + .name =3D TYPE_VHOST_USER_GPU, + .parent =3D TYPE_VIRTIO_GPU_BASE, + .instance_size =3D sizeof(VhostUserGPU), + .instance_init =3D vhost_user_gpu_instance_init, + .class_init =3D 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 late= r. + * 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 =3D VHOST_USER_VGA(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_USER_GPU); + + VIRTIO_VGA_BASE(dev)->vgpu =3D 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 =3D { + .name =3D TYPE_VHOST_USER_VGA, + .parent =3D TYPE_VIRTIO_VGA_BASE, + .instance_size =3D sizeof(struct VhostUserVGA), + .instance_init =3D 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 8a9d3457ec..9dee1bf20a 100644 --- a/vl.c +++ b/vl.c @@ -237,6 +237,7 @@ static struct { { .driver =3D "vmware-svga", .flag =3D &default_vga }, { .driver =3D "qxl-vga", .flag =3D &default_vga }, { .driver =3D "virtio-vga", .flag =3D &default_vga }, + { .driver =3D "vhost-user-vga", .flag =3D &default_vga }, }; =20 static QemuOptsList qemu_rtc_opts =3D { diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 5e60015b77..65ce98f767 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -40,8 +40,11 @@ obj-$(CONFIG_VGA) +=3D vga.o common-obj-$(CONFIG_QXL) +=3D qxl.o qxl-logger.o qxl-render.o =20 obj-$(CONFIG_VIRTIO_GPU) +=3D virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d= .o +obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VHOST_USER)) +=3D vhost-user= -gpu.o obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) +=3D virtio-gpu= -pci.o +obj-$(call land,$(CONFIG_VHOST_USER),$(call land,$(CONFIG_VIRTIO_GPU),$(CO= NFIG_VIRTIO_PCI))) +=3D vhost-user-gpu-pci.o obj-$(CONFIG_VIRTIO_VGA) +=3D virtio-vga.o +obj-$(call land,$(CONFIG_VIRTIO_VGA),$(CONFIG_VHOST_USER)) +=3D vhost-user= -vga.o virtio-gpu.o-cflags :=3D $(VIRGL_CFLAGS) virtio-gpu.o-libs +=3D $(VIRGL_LIBS) virtio-gpu-3d.o-cflags :=3D $(VIRGL_CFLAGS) --=20 2.18.0.129.ge3331758f1