From patchwork Thu May 5 17:19:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: John Johnson X-Patchwork-Id: 12839820 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DA6ACC433F5 for ; Thu, 5 May 2022 17:24:11 +0000 (UTC) Received: from localhost ([::1]:52018 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nmfD0-0002th-Sq for qemu-devel@archiver.kernel.org; Thu, 05 May 2022 13:24:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52536) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nmf0j-00063C-JT for qemu-devel@nongnu.org; Thu, 05 May 2022 13:11:34 -0400 Received: from mx0b-00069f02.pphosted.com ([205.220.177.32]:7178) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nmf0e-0002Br-RA for qemu-devel@nongnu.org; Thu, 05 May 2022 13:11:27 -0400 Received: from pps.filterd (m0246632.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 245FnNPo013665 for ; Thu, 5 May 2022 17:11:23 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : subject : date : message-id : in-reply-to : references : content-type : content-transfer-encoding : mime-version; s=corp-2021-07-09; bh=vgJTM+6/t7u+pXKc3NHsWJe1Vv8p8k3alDYFcnH/pDI=; b=o2exDFH+7E7TveSfSeBbbxSNcoX/EbzUKIHoNHEpkLxCDEutThq0cYvH73BB8UBhoF4C zpkEb+Dvhsy9njLybwjYCpL0eJ09wIcnF3iA0AEycR93NmfI7FmQNCpMphdoL5MGZodR hvshy+0j2sQOUi0qs1RDytI6/hxEM7e1CdtrYDU94eA/MN+HtbuQFWOdxoBp3spbpqaf 0sVQfZtnSHD6hf4aYzluCB3KmnSKv1GcR/7xprA7rwaAfQUv2hE2qX2eDy3+krFbs54C C93N9pxSv91W4fNO3l2mjkXoQEwDfomG5bssStn4NHAOq7oIvREPGLpjTwLfJc0xD1mb tA== Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.appoci.oracle.com [147.154.114.232]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3frvqsm1gd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Thu, 05 May 2022 17:11:22 +0000 Received: from pps.filterd (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (8.16.1.2/8.16.1.2) with SMTP id 245H1PHY001942 for ; Thu, 5 May 2022 17:11:22 GMT Received: from nam11-co1-obe.outbound.protection.outlook.com (mail-co1nam11lp2168.outbound.protection.outlook.com [104.47.56.168]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com with ESMTP id 3fs1a7amqq-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Thu, 05 May 2022 17:11:22 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=QSx/afDmkzSxL/5AdFxNBG3Bo94QSa5Mbt2fbOz7waRQyELEetQWsdzO7rCjGvOsxAGP3162tqYsPTUqLwbG9t82mOKCfpSEK30cJYxSM0O7kAzktamqWsVIGXeFCktFxE6Th6cKTK5ZmA4YAn9xYZVLBFO4d/f2WTHcVhbZV1Ik5+0DIydkBbwHnqdh1GRLcumINyloQCHQy1Yzqba+gzzXgC9LnfHkno16amzOPQokZ/hunsfxIkyiEsP533aKC1GOuME8vqrPf+lbQpi9Dy5MAl7RitsLzT1g2mRzF8+eH9t/mX888RE338cVe6gw4T3bsfGkStYcnUiR9bJNZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=vgJTM+6/t7u+pXKc3NHsWJe1Vv8p8k3alDYFcnH/pDI=; b=mZSB7Zegp+Ii9ptH8qgizBr3nlAKzCAaSuzJd0VJv6q+CX63mDiqJzoIMDXZUDYkErkPXGCuIjnpsoEi/RalEric5A/sm6f/I0+fc5T9n60mqcDl+KmGa9HbQL84KXZdNGkYCkmJ6o/P58riJgf47P5ENNMyWWD1hK2T7iV5lOMInBp5/H7cACFqhM+d6SiaDdJlEXmOGnosv5qJv/I03taShbaYplCjIfs7iCyYVJ07NvxQ5gixfaAXA/P/V5wQnhf/su9JaE1SLkuE1dwH7u3P6wEV0+Vefr+sFoYL+CBbV/NieB45+Rkbs8vp6MOPUZbjhDDpvfr6H7CYw6PtkA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=oracle.com; dmarc=pass action=none header.from=oracle.com; dkim=pass header.d=oracle.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.onmicrosoft.com; s=selector2-oracle-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=vgJTM+6/t7u+pXKc3NHsWJe1Vv8p8k3alDYFcnH/pDI=; b=VQ/oqCIWrr8TIXTkgCYgqDq81wrkQNlgzZc32XXaFJMpQiINjCxCFRU0ZwdkTQkZNFP9bPFrvp2dpVWe54Ei/TUJnpPP7CX3U0lsMpWSsUPW1PunlkmpSwuZIoUyzRGmd42h+zDf8DwZ27pygP4WTp9m2N+nODvL+I4lcZu0bd8= Received: from BYAPR10MB3255.namprd10.prod.outlook.com (2603:10b6:a03:156::22) by DM5PR10MB1867.namprd10.prod.outlook.com (2603:10b6:3:10b::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5206.24; Thu, 5 May 2022 17:11:19 +0000 Received: from BYAPR10MB3255.namprd10.prod.outlook.com ([fe80::cce6:1c15:c6bd:dd05]) by BYAPR10MB3255.namprd10.prod.outlook.com ([fe80::cce6:1c15:c6bd:dd05%7]) with mapi id 15.20.5206.027; Thu, 5 May 2022 17:11:19 +0000 From: John Johnson To: qemu-devel@nongnu.org Subject: [RFC v5 08/23] vfio-user: define socket receive functions Date: Thu, 5 May 2022 10:19:51 -0700 Message-Id: <13284a1a153e6791dc6afba2f4edf2ddf18c8d69.1651709440.git.john.g.johnson@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: References: X-ClientProxiedBy: BYAPR06CA0048.namprd06.prod.outlook.com (2603:10b6:a03:14b::25) To BYAPR10MB3255.namprd10.prod.outlook.com (2603:10b6:a03:156::22) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 061cfecf-c91c-4c59-0cb5-08da2eba44d3 X-MS-TrafficTypeDiagnostic: DM5PR10MB1867:EE_ X-Microsoft-Antispam-PRVS: X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: BcbmPST/M5oEg0nqP1efZ99k19G9eybXp101x0SyhYkeIseDlRgo50xxzPq3ZT/MepwLycYWpejPLArnmxwUtEc7vXkLubJJTlzD6I5u4PUmTdR3gX+6D9v9nvIPSwlR5Aerld9qwe7RPdTwDGZZ64rhGS4pK9CNzUQF9ZsmdRClfItqt6IWFAfz8ms6wY+Pq4UUlUGezEvTMRfWXA/8NbEcydpp3BQdC9lUlGSrkCXEXlslgyDtmy6MCFV4lXtZRow1UNmjARAqjZdGMZvxZYnV2h09YABfk+7rb6JifpVog522QTcQ4hPb0MRz35rec1cWn+NdXuxeZdT7oOV0XX+acM9d1F2gtMZ1PcjUrhBYmtE+q2uM5Hl/xQIM5oYX4F2e+tY8IvPw4LT9HpzTGC0C9ZvrhIXFm3peZ8OtPuUeeGSW6JDTYqrZlqrbpRVM2nfF6GjIJzxuvQPSOho4p06F6rkCgpr3louLQA2wZZQ15pKMpPozeCP9YL+ILlYZLdR7Z43VK7WCAjvnP68o1x76m+7PNNMyTv0ClATjDa/p1O/NQlzHohiOmdWTtG0nvC8DsUeuGHi9ShGpXNAsy/LPVJspKjpsqPicv2qOsTHntZKzWBZVw6wrfEBZnmx7VSDfPUUSnSM9TbZGqR8kURfJ1tfRPU5nYiQx4lUNT+frz8jPGSd+VRLrQ2i8BGtGdkABmOKO6NyLz1UMkZ/4uQ== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:BYAPR10MB3255.namprd10.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230001)(366004)(52116002)(6666004)(8676002)(66556008)(66946007)(66476007)(8936002)(38100700002)(38350700002)(5660300002)(86362001)(508600001)(6486002)(316002)(6506007)(186003)(83380400001)(36756003)(30864003)(2616005)(2906002)(26005)(6512007)(6916009); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?q?8prjLPD4YD9qm1C/KNZeEEXksVqw?= =?utf-8?q?IOQ3xcrszMRW8kozhd5vApI1yOTPWgiJkeENprwpluGfMo9p7EUzH1nlb2uluCAgb?= =?utf-8?q?VDM1TFv7HhP6O1fz0Imimh4FniXPpOcLhxpIacT0uK4RKyZ5KikqCNhHfqGp56EBU?= =?utf-8?q?UyZaKOhu7E1oErF/MXzengW4Z85WshKyhipFbB1jqpvXRCVLb1oLSfzFqmEBhKd7c?= =?utf-8?q?XtaMDHzbhC3v7cxB8bFxwe+mOg8D96OThWn6vbksDylhIqf3DGj/sproDQO/3Z7IE?= =?utf-8?q?31e9NOYSYjoE8LhaR1HJg6D47uiyV85sEdzEBjZvb/feKFba/BDYcJXCKMmqcdX3e?= =?utf-8?q?qToUHrtytm0xWhFi/rrojrzkxj3vIbiY4GSYMF+J4EjimDwP4aVgqODWplu6Mpxg1?= =?utf-8?q?1CVPWgcBtUipsURkInx9aEQFp9r+gkp5i9OXSlyzlXHwYO9DiNM/tuna7ZOZ3tWiu?= =?utf-8?q?6SPXFjtwf5boZwCD6eqPpH8Ln+5LJY1ZiA8hyPEsAu5PYaG9iLojYDxwZnnlyHgv+?= =?utf-8?q?QRBcHxkD3x2g0e0tN8LvoNn/GqPByiDOhKSBMgIJJLIYKDmHh1OX0goz1XwGEHKKW?= =?utf-8?q?lph2hMR9czcBKQi2hxIuiXDu5d+VqyKZLJkfEyse1hDA3OwYf4EfVtef5xETa6KrH?= =?utf-8?q?M3VCOpZz/fpCd7nS5EPlHWckR/3tm53qqS5quxDW8JCqchOi9vBmRDo/Y3LrGth4t?= =?utf-8?q?3i6U+BduszqySq69QWzHTOkjzsLR13U848gs7vrSOOKi+aeyUI+ApxhOTr8sHLcHg?= =?utf-8?q?FK/4m6GgxHl85mWRp6ILy7r5agzvhxJE4tG7XFvA/lRVGv9EzvkwPnvHJxS4NgPSz?= =?utf-8?q?jlM8ICAbk1YMAwNvGjPDcfpFdWuPiRfoolf1oatV7KaDDzMWMmNdtOAZXGKguk/00?= =?utf-8?q?vLooY02ElOyn5G3DAoZ4oWASmApL/RJP1pua76wfp1Dp92Lx0X/NevXNusMgkV58W?= =?utf-8?q?A/+i9dyq5IpLWAX7psjVbYltRmLfo4W9X1UJE76k44JTm5sv8g410EdZnm+BDtG1N?= =?utf-8?q?j0RVR11dBfUlkgalFRef4d6WNtgwk9Gc8lHDO7rixLCn5PyK/irn1bM++KlCboXu9?= =?utf-8?q?KxVBgp5IprCmapJ1+iNv3S1bv5BXaSKuise7JdnzeVgrzKYfXs5IrZxeCbmJ+gFP1?= =?utf-8?q?wcvr7IN/WIZGC3Kv17aIyp3y79uikeGIIdehtIkUXdPnG6Qxc6yzbh6DkXscezzfc?= =?utf-8?q?NWFWd83POZDB3BYpTjHRJxexyPwvRMMMIJ0hkwR2FVhdeui6Hph5xnlBDe+u2SiGE?= =?utf-8?q?bIyavpU7jCxsmivm5LMe15GlxU7GIc1QQH8LKfQngNtSL64zkHU1327fg99Wan9yv?= =?utf-8?q?Ox0K7qp0NVaf3ojrCXDLKFGRNfQoqPU84z6xfl/xtcaPmja0cn07aqzYZ5BREZZpu?= =?utf-8?q?0xaGw6bNuOeuj3EYH4PeypE8GDqJdwJjzzL++1pjZ/xRgm8oKRdkAZrKTobYkeoXm?= =?utf-8?q?0TypeRYunUSjE6HjFMD/ozUbyaaKuuIlQYqW8KU+ejIPZdvuQKRKRC8nNKszUsbKZ?= =?utf-8?q?coifIDNZtEYpm8diH19rUsjERTiQksD/7IJMXLLsWQTpC0eNr+r7wnDXZi1COT8YL?= =?utf-8?q?ahXsf5L9JY1rYWLArPZ/CcHMHIOsLtRgZLbY9jj6dAJuo4HcnUeryv9hijyTHMlo5?= =?utf-8?q?NdtJlsBzP9vnlT5AbJd4nn7eCpTgCT7D+KvaJYa7nsPAiI4vwp+/s=3D?= X-OriginatorOrg: oracle.com X-MS-Exchange-CrossTenant-Network-Message-Id: 061cfecf-c91c-4c59-0cb5-08da2eba44d3 X-MS-Exchange-CrossTenant-AuthSource: BYAPR10MB3255.namprd10.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 May 2022 17:11:18.0916 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4e2c6054-71cb-48f1-bd6c-3a9705aca71b X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: aX2HuHQ/yq1qUiK2rht0YzDyayMaw+gKJmJmG5H88/KZgzOxiQ6Zc7oGg9rylBZugm8w1fgQjifeRdIrMKa3kfqRvt1drb+79TuEwDFmuvQ= X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR10MB1867 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.486, 18.0.858 definitions=2022-05-05_06:2022-05-05, 2022-05-05 signatures=0 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 bulkscore=0 malwarescore=0 spamscore=0 mlxlogscore=999 mlxscore=0 suspectscore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2202240000 definitions=main-2205050118 X-Proofpoint-GUID: eo7M_APFv2pnP5LqbJq6iZClG2uLZmjF X-Proofpoint-ORIG-GUID: eo7M_APFv2pnP5LqbJq6iZClG2uLZmjF Received-SPF: pass client-ip=205.220.177.32; envelope-from=john.g.johnson@oracle.com; helo=mx0b-00069f02.pphosted.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Add infrastructure needed to receive incoming messages Signed-off-by: John G Johnson Signed-off-by: Elena Ufimtseva Signed-off-by: Jagannathan Raman --- hw/vfio/user-protocol.h | 54 +++++++ hw/vfio/user.h | 8 + hw/vfio/pci.c | 6 + hw/vfio/user.c | 404 ++++++++++++++++++++++++++++++++++++++++++++++++ MAINTAINERS | 1 + 5 files changed, 473 insertions(+) create mode 100644 hw/vfio/user-protocol.h diff --git a/hw/vfio/user-protocol.h b/hw/vfio/user-protocol.h new file mode 100644 index 0000000..d23877c --- /dev/null +++ b/hw/vfio/user-protocol.h @@ -0,0 +1,54 @@ +#ifndef VFIO_USER_PROTOCOL_H +#define VFIO_USER_PROTOCOL_H + +/* + * vfio protocol over a UNIX socket. + * + * Copyright © 2018, 2021 Oracle and/or its affiliates. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Each message has a standard header that describes the command + * being sent, which is almost always a VFIO ioctl(). + * + * The header may be followed by command-specific data, such as the + * region and offset info for read and write commands. + */ + +typedef struct { + uint16_t id; + uint16_t command; + uint32_t size; + uint32_t flags; + uint32_t error_reply; +} VFIOUserHdr; + +/* VFIOUserHdr commands */ +enum vfio_user_command { + VFIO_USER_VERSION = 1, + VFIO_USER_DMA_MAP = 2, + VFIO_USER_DMA_UNMAP = 3, + VFIO_USER_DEVICE_GET_INFO = 4, + VFIO_USER_DEVICE_GET_REGION_INFO = 5, + VFIO_USER_DEVICE_GET_REGION_IO_FDS = 6, + VFIO_USER_DEVICE_GET_IRQ_INFO = 7, + VFIO_USER_DEVICE_SET_IRQS = 8, + VFIO_USER_REGION_READ = 9, + VFIO_USER_REGION_WRITE = 10, + VFIO_USER_DMA_READ = 11, + VFIO_USER_DMA_WRITE = 12, + VFIO_USER_DEVICE_RESET = 13, + VFIO_USER_DIRTY_PAGES = 14, + VFIO_USER_MAX, +}; + +/* VFIOUserHdr flags */ +#define VFIO_USER_REQUEST 0x0 +#define VFIO_USER_REPLY 0x1 +#define VFIO_USER_TYPE 0xF + +#define VFIO_USER_NO_REPLY 0x10 +#define VFIO_USER_ERROR 0x20 + +#endif /* VFIO_USER_PROTOCOL_H */ diff --git a/hw/vfio/user.h b/hw/vfio/user.h index da92862..68a1080 100644 --- a/hw/vfio/user.h +++ b/hw/vfio/user.h @@ -11,6 +11,8 @@ * */ +#include "user-protocol.h" + typedef struct { int send_fds; int recv_fds; @@ -27,6 +29,7 @@ enum msg_type { typedef struct VFIOUserMsg { QTAILQ_ENTRY(VFIOUserMsg) next; + VFIOUserHdr *hdr; VFIOUserFDs *fds; uint32_t rsize; uint32_t id; @@ -66,6 +69,8 @@ typedef struct VFIOProxy { VFIOUserMsgQ incoming; VFIOUserMsgQ outgoing; VFIOUserMsg *last_nowait; + VFIOUserMsg *part_recv; + size_t recv_left; enum proxy_state state; } VFIOProxy; @@ -74,5 +79,8 @@ typedef struct VFIOProxy { VFIOProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp); void vfio_user_disconnect(VFIOProxy *proxy); +void vfio_user_set_handler(VFIODevice *vbasedev, + void (*handler)(void *opaque, VFIOUserMsg *msg), + void *reqarg); #endif /* VFIO_USER_H */ diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 8f65074..7ef11c0 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3387,6 +3387,11 @@ type_init(register_vfio_pci_dev_type) * vfio-user routines. */ +static void vfio_user_pci_process_req(void *opaque, VFIOUserMsg *msg) +{ + +} + /* * Emulated devices don't use host hot reset */ @@ -3433,6 +3438,7 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp) return; } vbasedev->proxy = proxy; + vfio_user_set_handler(vbasedev, vfio_user_pci_process_req, vdev); vbasedev->name = g_strdup_printf("VFIO user <%s>", udev->sock_name); vbasedev->dev = DEVICE(vdev); diff --git a/hw/vfio/user.c b/hw/vfio/user.c index c843f90..16b37cb 100644 --- a/hw/vfio/user.c +++ b/hw/vfio/user.c @@ -25,10 +25,26 @@ #include "sysemu/iothread.h" #include "user.h" +static uint64_t max_xfer_size; static IOThread *vfio_user_iothread; static void vfio_user_shutdown(VFIOProxy *proxy); +static VFIOUserMsg *vfio_user_getmsg(VFIOProxy *proxy, VFIOUserHdr *hdr, + VFIOUserFDs *fds); +static VFIOUserFDs *vfio_user_getfds(int numfds); +static void vfio_user_recycle(VFIOProxy *proxy, VFIOUserMsg *msg); +static void vfio_user_recv(void *opaque); +static int vfio_user_recv_one(VFIOProxy *proxy); +static void vfio_user_cb(void *opaque); + +static void vfio_user_request(void *opaque); + +static inline void vfio_user_set_error(VFIOUserHdr *hdr, uint32_t err) +{ + hdr->flags |= VFIO_USER_ERROR; + hdr->error_reply = err; +} /* * Functions called by main, CPU, or iothread threads @@ -40,10 +56,338 @@ static void vfio_user_shutdown(VFIOProxy *proxy) qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx, NULL, NULL, NULL); } +static VFIOUserMsg *vfio_user_getmsg(VFIOProxy *proxy, VFIOUserHdr *hdr, + VFIOUserFDs *fds) +{ + VFIOUserMsg *msg; + + msg = QTAILQ_FIRST(&proxy->free); + if (msg != NULL) { + QTAILQ_REMOVE(&proxy->free, msg, next); + } else { + msg = g_malloc0(sizeof(*msg)); + qemu_cond_init(&msg->cv); + } + + msg->hdr = hdr; + msg->fds = fds; + return msg; +} + +/* + * Recycle a message list entry to the free list. + */ +static void vfio_user_recycle(VFIOProxy *proxy, VFIOUserMsg *msg) +{ + if (msg->type == VFIO_MSG_NONE) { + error_printf("vfio_user_recycle - freeing free msg\n"); + return; + } + + /* free msg buffer if no one is waiting to consume the reply */ + if (msg->type == VFIO_MSG_NOWAIT || msg->type == VFIO_MSG_ASYNC) { + g_free(msg->hdr); + if (msg->fds != NULL) { + g_free(msg->fds); + } + } + + msg->type = VFIO_MSG_NONE; + msg->hdr = NULL; + msg->fds = NULL; + msg->complete = false; + QTAILQ_INSERT_HEAD(&proxy->free, msg, next); +} + +static VFIOUserFDs *vfio_user_getfds(int numfds) +{ + VFIOUserFDs *fds = g_malloc0(sizeof(*fds) + (numfds * sizeof(int))); + + fds->fds = (int *)((char *)fds + sizeof(*fds)); + + return fds; +} + /* * Functions only called by iothread */ +/* + * Process a received message. + */ +static void vfio_user_process(VFIOProxy *proxy, VFIOUserMsg *msg, bool isreply) +{ + + /* + * Replies signal a waiter, if none just check for errors + * and free the message buffer. + * + * Requests get queued for the BH. + */ + if (isreply) { + msg->complete = true; + if (msg->type == VFIO_MSG_WAIT) { + qemu_cond_signal(&msg->cv); + } else { + if (msg->hdr->flags & VFIO_USER_ERROR) { + error_printf("vfio_user_rcv: error reply on async request "); + error_printf("command %x error %s\n", msg->hdr->command, + strerror(msg->hdr->error_reply)); + } + /* youngest nowait msg has been ack'd */ + if (proxy->last_nowait == msg) { + proxy->last_nowait = NULL; + } + vfio_user_recycle(proxy, msg); + } + } else { + QTAILQ_INSERT_TAIL(&proxy->incoming, msg, next); + qemu_bh_schedule(proxy->req_bh); + } +} + +/* + * Complete a partial message read + */ +static int vfio_user_complete(VFIOProxy *proxy, Error **errp) +{ + VFIOUserMsg *msg = proxy->part_recv; + size_t msgleft = proxy->recv_left; + bool isreply; + char *data; + int ret; + + data = (char *)msg->hdr + (msg->hdr->size - msgleft); + while (msgleft > 0) { + ret = qio_channel_read(proxy->ioc, data, msgleft, errp); + + /* error or would block */ + if (ret <= 0) { + /* try for rest on next iternation */ + if (ret == QIO_CHANNEL_ERR_BLOCK) { + proxy->recv_left = msgleft; + } + return ret; + } + + msgleft -= ret; + data += ret; + } + + /* + * Read complete message, process it. + */ + proxy->part_recv = NULL; + proxy->recv_left = 0; + isreply = (msg->hdr->flags & VFIO_USER_TYPE) == VFIO_USER_REPLY; + vfio_user_process(proxy, msg, isreply); + + /* return positive value */ + return 1; +} + +static void vfio_user_recv(void *opaque) +{ + VFIOProxy *proxy = opaque; + + QEMU_LOCK_GUARD(&proxy->lock); + + if (proxy->state == VFIO_PROXY_CONNECTED) { + while (vfio_user_recv_one(proxy) == 0) { + ; + } + } +} + +/* + * Receive and process one incoming message. + * + * For replies, find matching outgoing request and wake any waiters. + * For requests, queue in incoming list and run request BH. + */ +static int vfio_user_recv_one(VFIOProxy *proxy) +{ + VFIOUserMsg *msg = NULL; + g_autofree int *fdp = NULL; + VFIOUserFDs *reqfds; + VFIOUserHdr hdr; + struct iovec iov = { + .iov_base = &hdr, + .iov_len = sizeof(hdr), + }; + bool isreply = false; + int i, ret; + size_t msgleft, numfds = 0; + char *data = NULL; + char *buf = NULL; + Error *local_err = NULL; + + /* + * Complete any partial reads + */ + if (proxy->part_recv != NULL) { + ret = vfio_user_complete(proxy, &local_err); + + /* still not complete, try later */ + if (ret == QIO_CHANNEL_ERR_BLOCK) { + return ret; + } + + if (ret <= 0) { + goto fatal; + } + /* else fall into reading another msg */ + } + + /* + * Read header + */ + ret = qio_channel_readv_full(proxy->ioc, &iov, 1, &fdp, &numfds, + &local_err); + if (ret == QIO_CHANNEL_ERR_BLOCK) { + return ret; + } + + /* read error or other side closed connection */ + if (ret <= 0) { + goto fatal; + } + + if (ret < sizeof(msg)) { + error_setg(&local_err, "short read of header"); + goto fatal; + } + + /* + * Validate header + */ + if (hdr.size < sizeof(VFIOUserHdr)) { + error_setg(&local_err, "bad header size"); + goto fatal; + } + switch (hdr.flags & VFIO_USER_TYPE) { + case VFIO_USER_REQUEST: + isreply = false; + break; + case VFIO_USER_REPLY: + isreply = true; + break; + default: + error_setg(&local_err, "unknown message type"); + goto fatal; + } + + /* + * For replies, find the matching pending request. + * For requests, reap incoming FDs. + */ + if (isreply) { + QTAILQ_FOREACH(msg, &proxy->pending, next) { + if (hdr.id == msg->id) { + break; + } + } + if (msg == NULL) { + error_setg(&local_err, "unexpected reply"); + goto err; + } + QTAILQ_REMOVE(&proxy->pending, msg, next); + + /* + * Process any received FDs + */ + if (numfds != 0) { + if (msg->fds == NULL || msg->fds->recv_fds < numfds) { + error_setg(&local_err, "unexpected FDs"); + goto err; + } + msg->fds->recv_fds = numfds; + memcpy(msg->fds->fds, fdp, numfds * sizeof(int)); + } + } else { + if (numfds != 0) { + reqfds = vfio_user_getfds(numfds); + memcpy(reqfds->fds, fdp, numfds * sizeof(int)); + } else { + reqfds = NULL; + } + } + + /* + * Put the whole message into a single buffer. + */ + if (isreply) { + if (hdr.size > msg->rsize) { + error_setg(&local_err, "reply larger than recv buffer"); + goto err; + } + *msg->hdr = hdr; + data = (char *)msg->hdr + sizeof(hdr); + } else { + if (hdr.size > max_xfer_size) { + error_setg(&local_err, "vfio_user_recv request larger than max"); + goto err; + } + buf = g_malloc0(hdr.size); + memcpy(buf, &hdr, sizeof(hdr)); + data = buf + sizeof(hdr); + msg = vfio_user_getmsg(proxy, (VFIOUserHdr *)buf, reqfds); + msg->type = VFIO_MSG_REQ; + } + + /* + * Read rest of message. + */ + msgleft = hdr.size - sizeof(hdr); + while (msgleft > 0) { + ret = qio_channel_read(proxy->ioc, data, msgleft, &local_err); + + /* prepare to complete read on next iternation */ + if (ret == QIO_CHANNEL_ERR_BLOCK) { + proxy->part_recv = msg; + proxy->recv_left = msgleft; + return ret; + } + + if (ret <= 0) { + goto fatal; + } + + msgleft -= ret; + data += ret; + } + + vfio_user_process(proxy, msg, isreply); + return 0; + + /* + * fatal means the other side closed or we don't trust the stream + * err means this message is corrupt + */ +fatal: + vfio_user_shutdown(proxy); + proxy->state = VFIO_PROXY_ERROR; + + /* set error if server side closed */ + if (ret == 0) { + error_setg(&local_err, "server closed socket"); + } + +err: + for (i = 0; i < numfds; i++) { + close(fdp[i]); + } + if (isreply && msg != NULL) { + /* force an error to keep sending thread from hanging */ + vfio_user_set_error(msg->hdr, EINVAL); + msg->complete = true; + qemu_cond_signal(&msg->cv); + } + error_prepend(&local_err, "vfio_user_recv: "); + error_report_err(local_err); + return -1; +} + static void vfio_user_cb(void *opaque) { VFIOProxy *proxy = opaque; @@ -59,6 +403,51 @@ static void vfio_user_cb(void *opaque) * Functions called by main or CPU threads */ +/* + * Process incoming requests. + * + * The bus-specific callback has the form: + * request(opaque, msg) + * where 'opaque' was specified in vfio_user_set_handler + * and 'msg' is the inbound message. + * + * The callback is responsible for disposing of the message buffer, + * usually by re-using it when calling vfio_send_reply or vfio_send_error, + * both of which free their message buffer when the reply is sent. + * + * If the callback uses a new buffer, it needs to free the old one. + */ +static void vfio_user_request(void *opaque) +{ + VFIOProxy *proxy = opaque; + VFIOUserMsgQ new, free; + VFIOUserMsg *msg, *m1; + + /* reap all incoming */ + QTAILQ_INIT(&new); + WITH_QEMU_LOCK_GUARD(&proxy->lock) { + QTAILQ_FOREACH_SAFE(msg, &proxy->incoming, next, m1) { + QTAILQ_REMOVE(&proxy->pending, msg, next); + QTAILQ_INSERT_TAIL(&new, msg, next); + } + } + + /* process list */ + QTAILQ_INIT(&free); + QTAILQ_FOREACH_SAFE(msg, &new, next, m1) { + QTAILQ_REMOVE(&new, msg, next); + proxy->request(proxy->req_arg, msg); + QTAILQ_INSERT_HEAD(&free, msg, next); + } + + /* free list */ + WITH_QEMU_LOCK_GUARD(&proxy->lock) { + QTAILQ_FOREACH_SAFE(msg, &free, next, m1) { + vfio_user_recycle(proxy, msg); + } + } +} + static QLIST_HEAD(, VFIOProxy) vfio_user_sockets = QLIST_HEAD_INITIALIZER(vfio_user_sockets); @@ -97,6 +486,7 @@ VFIOProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp) } proxy->ctx = iothread_get_aio_context(vfio_user_iothread); + proxy->req_bh = qemu_bh_new(vfio_user_request, proxy); QTAILQ_INIT(&proxy->outgoing); QTAILQ_INIT(&proxy->incoming); @@ -107,6 +497,18 @@ VFIOProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp) return proxy; } +void vfio_user_set_handler(VFIODevice *vbasedev, + void (*handler)(void *opaque, VFIOUserMsg *msg), + void *req_arg) +{ + VFIOProxy *proxy = vbasedev->proxy; + + proxy->request = handler; + proxy->req_arg = req_arg; + qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx, + vfio_user_recv, NULL, proxy); +} + void vfio_user_disconnect(VFIOProxy *proxy) { VFIOUserMsg *r1, *r2; @@ -122,6 +524,8 @@ void vfio_user_disconnect(VFIOProxy *proxy) } object_unref(OBJECT(proxy->ioc)); proxy->ioc = NULL; + qemu_bh_delete(proxy->req_bh); + proxy->req_bh = NULL; proxy->state = VFIO_PROXY_CLOSING; QTAILQ_FOREACH_SAFE(r1, &proxy->outgoing, next, r2) { diff --git a/MAINTAINERS b/MAINTAINERS index cd44f91..c81f8b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1964,6 +1964,7 @@ S: Supported F: docs/devel/vfio-user.rst F: hw/vfio/user.c F: hw/vfio/user.h +F: hw/vfio/user-protocol.h vhost M: Michael S. Tsirkin