From nobody Fri Sep 25 09:19:46 2026 Received: from mail-pf1-f227.google.com (mail-pf1-f227.google.com [209.85.210.227]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7A1064963BA for ; Mon, 14 Sep 2026 20:24:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.227 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789417459; cv=none; b=cR4z8HzaR8i0kD9FkEHrSso0sBWt+xbLtGzW3JKc5KE14jlL3aUf+tQgKO0IdMlmRynavvKktQ0Al8t0jX7a7+SJva1PscAyKB9Y+sJzbLo87QZWgMdkRa1OXexoiTLPoEI2xPQUw4iNsjukGOqQG/ZBqBhqAWOewTZWU9USJso= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789417459; c=relaxed/simple; bh=MMDykQzy7x7p66o0iMs9Sx0TXt7mVPc64bBKVA3boHE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VOK9YJAjYaQAHdlyVL+IC0pmO75mFTVRIN6B6dE7xX7xPDik7MGbpIlosCFEO9PWCOgARZAjmmqnLCxmcaFZ7wqITcGlvjdyH31uM3F6x5CNKpWTnWwFJ7q4xrAbRimsKiIWWTERT46DBGUHepLpGoQP+7eWDH6HfgxVFewzZTw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com; spf=fail smtp.mailfrom=broadcom.com; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b=JDKS3rqq; arc=none smtp.client-ip=209.85.210.227 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=broadcom.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="JDKS3rqq" Received: by mail-pf1-f227.google.com with SMTP id d2e1a72fcca58-8692be1cda4so3125498b3a.1 for ; Mon, 14 Sep 2026 13:24:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789417457; x=1790022257; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=5am8jY+Eh+kLQoKuHV0GYjrdnQEpm2u3B816c/P3fZI=; b=A2IaBl7pu/TN2apAa8pzVLJ8+h7WmhBK+yOB+xkDRwIxQlLfwI1zw5SB6LB/ctov4M UPjzfCIQ7DwQ8fldzRrtk2U8kg7RNEp/5lilDuHpJDmkqrkVvjKpgmeUKEHHKquwP9xt SB8nC+eWhcz0V06YxHxYSRDdb4avPlEp29x//pRXhMnI9+D6349IJNlfYKhGoZMQk0yj gNS2VoiWtF3gDFUiqOSXVoeC7PcPUZ5rpHiCpNmwtwz71cvDZhgAJHVKCslqYNfDEcEm 5hVHnZao2W0Q6/gSMRhEI8u1feD0kPdbAND5kE4B1s5x2iFw1L23KrAI7Ci6XQ3Df8bx TbMQ== X-Forwarded-Encrypted: i=1; AKwUvBxw9cWDJPaDjLHEhamLguj/n+TrgGM5bf85F4wavNkPKBAhkD1MxNVSx1Myevos+ApBs4ehurT11x0/lsw=@vger.kernel.org X-Gm-Message-State: AFuF++no4eAD+o6NHOYzJ+zqxk1StQ8lUUZJN/sDyDma96/hz7FWkGoT AaElhXqivnhxvBnWmzix2sCT7HYoQDyqsu1jyUZ5sNzI2rBjHgw4l4gZQd69uyVyWFKRlKoG112 NCHXw7y5r8m8u1LyToBTjAdPE6PUdZTpP6N47lGrHzKSlcnN7Avga1CxSifGD3oB3rsBleaZwqv Wrov244qgJT2dflHYA/I7dGKYJxGXqEH76IuGoyW28vAw337ggqUPbp/QcUf4uz23qsj8BJpGRq uu/IAchFCxdv3mdVIM1WA== X-Gm-Gg: AYBFou2fbsi//y007LQMUVoe8qRm+2WiXOlGRNmrGwa3QxoqFYJwhqb6htUO8qTmAAw FB975fY55qLLbB7t7qCmJMRjFrlSlz6Vi5W438Ge0ruHcYX+eFOw4bD4+XNU4jHTMsN7b0Uw59a XaHzAX849c3JpOPpe34BHNtB8RRb/CTDYGbMLTefBeuaCvkXAX4nXA0G1dRoFbuG8r0NJqMYbm3 h11g8uYCLBId+ESK+Er+7SYxxSMfacVpdhAclgpTTPsi3JAwUXuhsNhgO7BkMKqR97vujYMEurq O+GQcZ8+Kza6u1uECsrpZ+a7E0T7A1Wu01ev+4Dkz8MW0/nyqsEtpp7nRdaKr+83dJpe2+wmdMx CET1gCETu/Q5suTHmJw7nBgkkJAKcI6xjL7oZBK8Px9bZ/VaH4O4Jn07nLfNAt/UsYVhS9h3X6P 4M6QQ+mn8LYDbgOIu8hQrGugGCCTuPrMux6SzVcQ== X-Received: by 2002:a05:6a00:4096:b0:84a:29a7:f3b1 with SMTP id d2e1a72fcca58-86f85107ee3mr8681456b3a.16.1789417456511; Mon, 14 Sep 2026 13:24:16 -0700 (PDT) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-29.dlp.protect.broadcom.com. [144.49.247.29]) by smtp-relay.gmail.com with ESMTPS id 41be03b00d2f7-cc4c62a4114sm4644967a12.1.2026.09.14.13.24.15 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 14 Sep 2026 13:24:16 -0700 (PDT) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-ot1-f71.google.com with SMTP id 46e09a7af769-7f4e0b45e4bso4542788a34.2 for ; Mon, 14 Sep 2026 13:24:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1789417455; x=1790022255; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=5am8jY+Eh+kLQoKuHV0GYjrdnQEpm2u3B816c/P3fZI=; b=JDKS3rqqEQImpy9+9F75bbUuu6e9gTTAY+kKa6GnTewaqNikUPSs0jXzipxY1c3WTc 3OBZbiO8oxDrPF5SA7yWKYdBRnhd9anOzsukhUuM2eFwUMwRFryKBWOQbzYl8CzVqh0R 4V/5ZrnK+ERmZAVYUmKKDtToQ3QbOBq6h7qM4= X-Forwarded-Encrypted: i=1; AKwUvBxdwBsvwAHXzrVe/dizCW996ZOXvFiX/dUMtJ3F9u0kwtdzv5fZ8Ga+pKKpYNxO5aD2V0Yj2DC0DI2ayT0=@vger.kernel.org X-Received: by 2002:a05:6820:1899:b0:6b1:9f9d:79f3 with SMTP id 006d021491bc7-6c53fd76a77mr2393528eaf.17.1789417454681; Mon, 14 Sep 2026 13:24:14 -0700 (PDT) X-Received: by 2002:a05:6820:1899:b0:6b1:9f9d:79f3 with SMTP id 006d021491bc7-6c53fd76a77mr2393506eaf.17.1789417454184; Mon, 14 Sep 2026 13:24:14 -0700 (PDT) Received: from lvn-dbc2489.lvn.broadcom.net ([192.19.161.250]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-47df8699bc6sm11623741fac.3.2026.09.14.13.24.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 13:24:13 -0700 (PDT) From: Rishi Chhibber To: gregkh@linuxfoundation.org, arnd@arndb.de Cc: bryan-bt.tan@broadcom.com, vishnu.dasa@broadcom.com, corbet@lwn.net, skhan@linuxfoundation.org, shuah@kernel.org, rdunlap@infradead.org, bcm-kernel-feedback-list@broadcom.com, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, ajay.kaher@broadcom.com, alexey.makhalov@broadcom.com, vamsi-krishna.brahmajosyula@broadcom.com, yin.ding@broadcom.com, tapas.kundu@broadcom.com, Rishi Chhibber Subject: [PATCH v3 1/4] misc: vmw_vmci: Reserve a datagram resource id for zero-copy buffer sharing Date: Mon, 14 Sep 2026 13:22:06 -0700 Message-ID: <137107b03a5e76ec39a0a7f453db892044ccb108.1789413109.git.rishi.chhibber@broadcom.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-DetectorID-Processed: b00c1d49-9d2e-4205-b15f-d015386d3d5e Content-Type: text/plain; charset="utf-8" Summary of changes: - Add VMCI_VMWZC_DST_RID to the reserved hypervisor datagram resource id enum and bump VMCI_RESOURCE_MAX accordingly The hypervisor-side zero-copy buffer sharing service occupies its own resource id in the hypervisor datagram namespace. Reserve a name for it alongside the existing entries rather than leaving callers to open-code the number, following the procedure described in that enum's own comment: the set of resource ids available in the hypervisor is fixed and statically known, and a new caller extends it by incrementing the maximum. VMCI_RESOURCE_MAX has no in-tree users, so the bump does not affect existing code. The new entry likewise has no in-tree user until the vmw_zerocopy driver, added later in this series, references it. Signed-off-by: Rishi Chhibber Reviewed-by: Alexey Makhalov Reviewed-by: Vishnu Dasa --- include/linux/vmw_vmci_defs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/vmw_vmci_defs.h b/include/linux/vmw_vmci_defs.h index 60c9eacd2cf3..4435d2ff1241 100644 --- a/include/linux/vmw_vmci_defs.h +++ b/include/linux/vmw_vmci_defs.h @@ -179,7 +179,8 @@ enum { VMCI_UNITY_PBRPC_REGISTER =3D 14, VMCI_RPC_PRIVILEGED =3D 15, VMCI_RPC_UNPRIVILEGED =3D 16, - VMCI_RESOURCE_MAX =3D 17, + VMCI_VMWZC_DST_RID =3D 17, + VMCI_RESOURCE_MAX =3D 18, }; =20 /* --=20 2.52.0 From nobody Fri Sep 25 09:19:46 2026 Received: from mail-qt1-f227.google.com (mail-qt1-f227.google.com [209.85.160.227]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ADDBF49AA48 for ; Mon, 14 Sep 2026 20:24:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.227 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789417462; cv=none; b=gMBomiB8sCBtuXFSSLPOH26j/xWOVt62319XgC7bcyNeJFfVp4pMPe3zRfG4LbmmxJeuA70HwU5kTuV6k1YwsbmpLrGX92lGJZTiNyJVPRYVqVF7OGGK49fOA5EFIqowuBBJm9RyvLbA6AGHwvSIB1iZF26YN4lF+YWnCTbxHXQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789417462; c=relaxed/simple; bh=WK0q1l3H1KJTu4dD6ybH59grBktww0sexuUOeNOEpOU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CdAr6GqVPeWrQInDxgOdvWrBOnLhf8s2jRjpjKWEZCBWf74kQMTAwaJM3G/cv/WbFI0LQL6V7f+BlLNFZXsqNmaN+Ah4zJSe/hSVCC2N7ttsy7GsHAJripPB9XyfMytm5WtLbcGSXpMhSUy3x1D6RNaK6EtaF7eQNLLzMSXuDgY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com; spf=fail smtp.mailfrom=broadcom.com; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b=eW1kzfNe; arc=none smtp.client-ip=209.85.160.227 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=broadcom.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="eW1kzfNe" Received: by mail-qt1-f227.google.com with SMTP id d75a77b69052e-5310ab4cba2so3375531cf.3 for ; Mon, 14 Sep 2026 13:24:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789417458; x=1790022258; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=oakn8qxLip+m26kgiqtIpS/fNC1BBRey/OW7it8+tVg=; b=XIdtcmwUKg60RRf3XN5Fgl/gWHNWzi4yQlmeh59Wp1wUyB46ZI3mUhxk4jipJQLbol 7YkDDJSCqu2MRPMGEY/UW5n8xg7GmXH3t4/kCBsbFNpDAHJbSFx5S+HF7CcNcMtq0vjC sHqXUQU+9wMcSHibRSHUYQq/OMNbbODHq0PZ/BKHFlM7ciU6wqzN5zSCkkyj6hsSHS05 qyMuw8L6LGdOILguiLYo7k62K86gfEupa+KdXqjqxtFidwVTbuT8kIVtBA/zaS0ARQvf yHdlIbDTCnL2h5Vj/HarOFxLoVZLekyEh4Tu/YlefbGmcvbSaEAmeyy7LhlND1rEqkiO rjPw== X-Forwarded-Encrypted: i=1; AKwUvByqXssvr15slIWadmYD3ZjouBzq4PtL83A0PZHda8FRSA74VuyIaOTnJzVov1Weo+mOIf2GAongWQOiqzM=@vger.kernel.org X-Gm-Message-State: AFuF++l1d91RV3XX3/CuR0L0aolbMIGyT48L+LvXEqYFk4K93gTrD4zD 3SIY19GibG9zLo4NnpKZU/3YKmi/MyaVa0/QXpjCdyDvqX0Co8aXAiMepT20rAQyo/Ri56nZQrD f+PRqn0W+N4bl1960uTEwZlfRCfUKiD7087oYuyOzhHvles2z8hW5ncyXsf5q8H9w5JddauVzuU hG5GAspJuH21dQ7PNSpkf9GPDB2sMt4j2l0uQjW/Xwceo8g2QsQBksywkuRxFYVoBz4Nzb3RiRK odDT4brbKtEKWRnkeAdOA== X-Gm-Gg: AYBFou3sdL0YBoz6D+ztE5m2JrzpuCsIWbEi261xrZxpykGMH34HNzLb75LNS6NsFp6 8m/OZF4W+1A6AcJEsCzzHrjPenfj0fedc6Gov7xeqv2kdN61O8ZhfmBGRaagA1qQuAXMMeWzvHD eJTBASgUfEAKQePlHpy336fWFq/A60g4k4kpinrnVJYM1OCtmVrvOmY/sKUI6l3FCSL477+Vo2k OVDK8uMod7DSXMHnXZRdJFQuecXG0GFJhQaN7o/8M5KEGZv5WLn/v8fd79ZUOAAjFJ7MaNZMXI9 FWhyWUD27V5cdgal5dJhf7OBoGZCEehlsX6AOC4IZqhiQgTJolx04xVsFHVW14vfbDIukcIruP0 9iQfvhyg9y/ntaMvqtmI+k0I6BPOYJX/6DHQ+QPCykBdMdSB3Qx6GguEBhWxEtu7uYnPjfNY/fg sGeMCHEJ7xAw4P2AanZJW4+tNqDrMJcTMG0DQEoQ== X-Received: by 2002:ac8:5908:0:b0:52f:bfb3:ed3d with SMTP id d75a77b69052e-5310cf40d5fmr60979301cf.25.1789417458382; Mon, 14 Sep 2026 13:24:18 -0700 (PDT) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-25.dlp.protect.broadcom.com. [144.49.247.25]) by smtp-relay.gmail.com with ESMTPS id d75a77b69052e-530ca4ee412sm1428241cf.14.2026.09.14.13.24.17 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 14 Sep 2026 13:24:18 -0700 (PDT) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-oo1-f72.google.com with SMTP id 006d021491bc7-6b1a3f01d2aso5494656eaf.1 for ; Mon, 14 Sep 2026 13:24:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1789417457; x=1790022257; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=oakn8qxLip+m26kgiqtIpS/fNC1BBRey/OW7it8+tVg=; b=eW1kzfNeUC3oOJFfDQd6bRj3VkdKfoKcFjKH7cnq+xMdPmAWynjPkH3dj4qnwykDQP usELQmYb+83OdKY75fhSlyq8iR5L0RMMeY8559FQe0yaHWOjU1CVkHTmJOxDCvml3Vq+ e3dFNQdYIaxBhSkSZSqzJX+0R3U4J2RTMTSIk= X-Forwarded-Encrypted: i=1; AKwUvByfGQn/W5DOF3QoQVZrmP0fUqDlhrJPYrsDtvEgmHaqkreu68/h/oTkTQJfjGxQWMui7o/UXWDUsp72GK4=@vger.kernel.org X-Received: by 2002:a05:6820:1527:b0:6bd:d2ad:55a1 with SMTP id 006d021491bc7-6c53fe7e170mr2451159eaf.9.1789417456977; Mon, 14 Sep 2026 13:24:16 -0700 (PDT) X-Received: by 2002:a05:6820:1527:b0:6bd:d2ad:55a1 with SMTP id 006d021491bc7-6c53fe7e170mr2451131eaf.9.1789417456300; Mon, 14 Sep 2026 13:24:16 -0700 (PDT) Received: from lvn-dbc2489.lvn.broadcom.net ([192.19.161.250]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-47df8699bc6sm11623741fac.3.2026.09.14.13.24.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 13:24:15 -0700 (PDT) From: Rishi Chhibber To: gregkh@linuxfoundation.org, arnd@arndb.de Cc: bryan-bt.tan@broadcom.com, vishnu.dasa@broadcom.com, corbet@lwn.net, skhan@linuxfoundation.org, shuah@kernel.org, rdunlap@infradead.org, bcm-kernel-feedback-list@broadcom.com, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, ajay.kaher@broadcom.com, alexey.makhalov@broadcom.com, vamsi-krishna.brahmajosyula@broadcom.com, yin.ding@broadcom.com, tapas.kundu@broadcom.com, Rishi Chhibber Subject: [PATCH v3 2/4] misc: vmw_zerocopy: Add VMware zero-copy buffer sharing driver Date: Mon, 14 Sep 2026 13:22:07 -0700 Message-ID: <9318be9d4da2392586d4ce72428592a3e5a02b99.1789413109.git.rishi.chhibber@broadcom.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-DetectorID-Processed: b00c1d49-9d2e-4205-b15f-d015386d3d5e Content-Type: text/plain; charset="utf-8" Summary of changes: - Add drivers/misc/vmw_zerocopy_core.c: the misc character device /dev/vmw_zc, its single ioctl, page pinning and PFN collection - Add drivers/misc/vmw_zerocopy_vmci.c: the VMCI datagram transport backend - Add drivers/misc/vmw_zerocopy_priv.h: the wire-format message structs and the struct vmw_zc_transport_ops interface that joins the two - Add include/uapi/linux/vmw_zerocopy.h: struct vmw_zc_guest_message and VMW_ZC_IOCTL_MSG - Register ioctl magic 0xDC in Documentation/userspace-api/ioctl/ioctl-number.rst - Add the VMW_ZC Kconfig symbol and a MAINTAINERS entry This driver implements a misc character device (/dev/vmw_zc) that pins guest userspace pages and transmits their physical frame numbers (PFNs) to a VMware hypervisor-side peer. The payload itself is never transferred. What crosses to the hypervisor is a list of guest physical frame numbers for pages pinned in place, so the hypervisor reads the buffer directly out of guest memory. vsock and virtio are copying transports: both move the bytes through a ring or a socket buffer, which is precisely the copy this interface exists to avoid. The VMCI datagram carries only the PFN descriptor and never the data, which is why an existing standard transport cannot serve this purpose. The destination is deliberately not part of the UAPI. It is a VMCI resource id in the hypervisor context, and that namespace belongs to the platform: the low ids are the hypervisor's own control entry points, and vmci_datagram_send() dispatches from an in-kernel sender, so the check that stops userspace from addressing the hypervisor does not apply here. A device node that unprivileged userspace can open must therefore not let userspace name a destination, or it becomes an unfiltered writer onto the hypervisor's control namespace. Fixing the destination in the driver removes that reachability by construction rather than by validation. Delivery is abstracted behind a small transport interface so that VMCI, the only backend today, is not depended on directly by the ioctl path. The metadata buffer is released with unpin_user_pages_dirty_lock(..., true). The hypervisor stores its result through the physical frame, so neither the guest page table nor the folio records the write and the result can be lost to writeback or reclaim; this is the same fix as commit 779055842da5 ("xen/gntdev.c: Mark pages as dirty") and the pattern used by drivers/xen/privcmd.c. The read-only data buffer keeps the plain path. Signed-off-by: Rishi Chhibber Reviewed-by: Alexey Makhalov Reviewed-by: Vishnu Dasa --- .../userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 10 + drivers/misc/Kconfig | 23 ++ drivers/misc/Makefile | 2 + drivers/misc/vmw_zerocopy_core.c | 267 ++++++++++++++++++ drivers/misc/vmw_zerocopy_priv.h | 66 +++++ drivers/misc/vmw_zerocopy_vmci.c | 132 +++++++++ include/uapi/linux/vmw_zerocopy.h | 67 +++++ 8 files changed, 568 insertions(+) create mode 100644 drivers/misc/vmw_zerocopy_core.c create mode 100644 drivers/misc/vmw_zerocopy_priv.h create mode 100644 drivers/misc/vmw_zerocopy_vmci.c create mode 100644 include/uapi/linux/vmw_zerocopy.h diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documenta= tion/userspace-api/ioctl/ioctl-number.rst index 2fc53093752d..f55998d5e270 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -396,6 +396,7 @@ Code Seq# Include File = Comments 0xCD 01 linux/reiserfs_fs.h Dea= d since 6.13 0xCE 01-02 uapi/linux/cxl_mem.h Com= pute Express Link Memory Devices 0xCF 02 fs/smb/client/cifs_ioctl.h +0xDC 01 uapi/linux/vmw_zerocopy.h VMw= are zero-copy buffer sharing 0xDD 00-3F ZFC= P device driver see drivers/s390/scsi/ 0xE5 00-3F linux/fuse.h diff --git a/MAINTAINERS b/MAINTAINERS index c2414447892c..d683336b30d8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -29228,6 +29228,16 @@ L: linux-kernel@vger.kernel.org S: Supported F: net/vmw_vsock/vmci_transport* =20 +VMWARE ZEROCOPY DRIVER +M: Rishi Chhibber +R: Broadcom internal kernel review list +L: linux-kernel@vger.kernel.org +S: Supported +F: Documentation/misc-devices/vmw_zerocopy.rst +F: drivers/misc/vmw_zerocopy* +F: include/uapi/linux/vmw_zerocopy.h +F: tools/testing/selftests/drivers/misc/vmw_zerocopy/ + VOCORE VOCORE2 BOARD M: Harvey Hunt L: linux-mips@vger.kernel.org diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 7364931dad3a..cf48c29db35e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -359,6 +359,29 @@ config VMWARE_BALLOON To compile this driver as a module, choose M here: the module will be called vmw_balloon. =20 +config VMW_ZC + tristate "VMware zero-copy buffer sharing device" + depends on VMWARE_VMCI && HYPERVISOR_GUEST && !X86_MEM_ENCRYPT + help + This driver implements a character device (/dev/vmw_zc) that + allows guest userspace applications to share pinned memory + buffers with a VMware hypervisor-side peer using the VMCI + datagram interface. + + Applications submit buffers via ioctl(). The driver pins the + user pages and transmits their physical page frame numbers to + the peer, enabling zero-copy data transfer between the guest + and the hypervisor without an intermediate copy. + + This driver is not compatible with guests that use memory + encryption (AMD SEV-SNP or Intel TDX), as the hypervisor + cannot read encrypted guest physical memory. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called vmw_zerocopy. + config PCH_PHUB tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" select GENERIC_NET_UTILS diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e8d8d5d88c0d..eda927fd68dd 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -62,6 +62,8 @@ obj-$(CONFIG_TMR_MANAGER) +=3D xilinx_tmr_manager.o obj-$(CONFIG_TMR_INJECT) +=3D xilinx_tmr_inject.o obj-$(CONFIG_TPS6594_ESM) +=3D tps6594-esm.o obj-$(CONFIG_TPS6594_PFSM) +=3D tps6594-pfsm.o +obj-$(CONFIG_VMW_ZC) +=3D vmw_zerocopy.o +vmw_zerocopy-y :=3D vmw_zerocopy_core.o vmw_zerocopy_vmci.o obj-$(CONFIG_NSM) +=3D nsm.o obj-$(CONFIG_MARVELL_CN10K_DPI) +=3D mrvl_cn10k_dpi.o lan966x-pci-objs :=3D lan966x_pci.o diff --git a/drivers/misc/vmw_zerocopy_core.c b/drivers/misc/vmw_zerocopy_c= ore.c new file mode 100644 index 000000000000..bf5ab20ff1a0 --- /dev/null +++ b/drivers/misc/vmw_zerocopy_core.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2026 Broadcom. All Rights Reserved. The term + * "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +#include "vmw_zerocopy_priv.h" + +/* Compile-time transport selection; a second backend swaps this pointer. = */ +static const struct vmw_zc_transport_ops *vmw_zc_transport =3D &vmw_zc_vmc= i_transport; + +static long vmw_zc_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); + +static const struct file_operations vmw_zc_fops =3D { + .owner =3D THIS_MODULE, + .unlocked_ioctl =3D vmw_zc_ioctl, + .compat_ioctl =3D compat_ptr_ioctl, +}; + +/* + * 0644: any local user may open this device, but that only lets them + * pin their own memory and reach VMCI_VMWZC_DST_RID, a destination + * fixed by the driver. + */ +static struct miscdevice vmw_zc_misc =3D { + .minor =3D MISC_DYNAMIC_MINOR, + .name =3D VMW_ZC_DEVICE_NAME, + .fops =3D &vmw_zc_fops, + .mode =3D 0644, +}; + +/* + * @make_dirty must be true for any buffer the peer wrote into: it stores + * through the physical frame, so nothing marks the page dirty and the res= ult + * would be lost to writeback or reclaim. + */ +static void vmw_zc_unpin_user_pages(struct page **pages, int num_pages, + bool make_dirty) +{ + if (num_pages <=3D 0) + return; + + unpin_user_pages_dirty_lock(pages, num_pages, make_dirty); +} + +/* @pages must have room for VMW_ZC_MAX_PAGES entries. */ +static int vmw_zc_pin_user_pages(void __user *user_buf, size_t size, + struct page **pages, int *num_pages, + bool writable) +{ + unsigned long start_addr =3D (unsigned long)user_buf; + unsigned int gup_flags =3D writable ? FOLL_WRITE : 0; + int nr_pages; + int ret; + + if (!access_ok(user_buf, size)) { + dev_dbg(vmw_zc_misc.this_device, + "buffer not in user address space: 0x%lx + %zu\n", + start_addr, size); + return -EFAULT; + } + + nr_pages =3D DIV_ROUND_UP(offset_in_page(user_buf) + size, PAGE_SIZE); + + if ((unsigned long)nr_pages > VMW_ZC_MAX_PAGES) { + dev_dbg(vmw_zc_misc.this_device, + "buffer spans too many pages: %d > %lu\n", + nr_pages, VMW_ZC_MAX_PAGES); + return -EINVAL; + } + + ret =3D pin_user_pages_fast(start_addr & PAGE_MASK, nr_pages, gup_flags, + pages); + if (ret < 0) + return ret; + + if (ret !=3D nr_pages) { + /* Nothing was sent to the peer yet, so nothing was written. */ + vmw_zc_unpin_user_pages(pages, ret, false); + return -EFAULT; + } + + *num_pages =3D nr_pages; + return 0; +} + +/* + * Pin @buffer and optional @metadata and send PFN layout to the peer. + * Either buffer or metadata must exist. + */ +static int vmw_zc_send_user_buffer_msg(void __user *buffer, u32 buffer_len, + void __user *metadata, u32 metadata_len) +{ + int ret; + int i; + struct vmw_zc_host_message msg =3D { }; + struct page *buffer_pages[VMW_ZC_MAX_PAGES]; + struct page *metadata_pages[VMW_ZC_MAX_PAGES]; + int num_buffer_pages =3D 0; + int num_metadata_pages =3D 0; + + if (!buffer && !metadata) { + dev_dbg(vmw_zc_misc.this_device, + "neither buffer nor metadata provided\n"); + return -EINVAL; + } + + if (buffer) { + if (buffer_len =3D=3D 0 || buffer_len > VMW_ZC_MAX_BUFFER_SIZE) { + dev_dbg(vmw_zc_misc.this_device, + "invalid buffer size: %u (expected between 1-%u)\n", + buffer_len, VMW_ZC_MAX_BUFFER_SIZE); + return -EINVAL; + } + ret =3D vmw_zc_pin_user_pages(buffer, buffer_len, buffer_pages, + &num_buffer_pages, false); + if (ret) + return ret; + } + + if (metadata) { + if (metadata_len =3D=3D 0 || + metadata_len > VMW_ZC_MAX_BUFFER_SIZE) { + dev_dbg(vmw_zc_misc.this_device, + "invalid metadata size: %u (expected between 1-%u)\n", + metadata_len, VMW_ZC_MAX_BUFFER_SIZE); + ret =3D -EINVAL; + goto out_unpin; + } + ret =3D vmw_zc_pin_user_pages(metadata, metadata_len, + metadata_pages, + &num_metadata_pages, true); + if (ret) + goto out_unpin; + } + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + + if (buffer) { + msg.body.user_buf.data.offset =3D offset_in_page(buffer); + msg.body.user_buf.data.length =3D buffer_len; + msg.body.user_buf.data.num_pages =3D num_buffer_pages; + for (i =3D 0; i < num_buffer_pages; i++) { + msg.body.user_buf.data.page_pfns[i] =3D + page_to_pfn(buffer_pages[i]); + } + } + + if (metadata) { + msg.body.user_buf.metadata.offset =3D offset_in_page(metadata); + msg.body.user_buf.metadata.length =3D metadata_len; + msg.body.user_buf.metadata.num_pages =3D num_metadata_pages; + for (i =3D 0; i < num_metadata_pages; i++) { + msg.body.user_buf.metadata.page_pfns[i] =3D + page_to_pfn(metadata_pages[i]); + } + } + + ret =3D vmw_zc_transport->send(&msg); + +out_unpin: + /* Metadata is written by the peer; the data buffer is read-only. */ + vmw_zc_unpin_user_pages(metadata_pages, num_metadata_pages, true); + vmw_zc_unpin_user_pages(buffer_pages, num_buffer_pages, false); + return ret; +} + +static int vmw_zc_send_raw_msg(const u8 *raw, u32 raw_len) +{ + struct vmw_zc_host_message msg =3D { }; + + if (raw_len =3D=3D 0 || raw_len > VMW_ZC_MAX_RAW_BUFFER_LEN) { + dev_dbg(vmw_zc_misc.this_device, + "invalid raw size: %u (max %u)\n", + raw_len, VMW_ZC_MAX_RAW_BUFFER_LEN); + return -EINVAL; + } + + msg.message_type =3D VMW_ZC_MSG_RAW; + memcpy(msg.body.raw.raw, raw, raw_len); + + return vmw_zc_transport->send(&msg); +} + +static long vmw_zc_ioctl(struct file *file, unsigned int cmd, unsigned lon= g arg) +{ + int ret =3D 0; + void __user *buf, *meta; + u32 buf_len, meta_len; + struct vmw_zc_guest_message guest_msg; + + if (cmd !=3D VMW_ZC_IOCTL_MSG) + return -ENOTTY; + + if (copy_from_user(&guest_msg, (void __user *)arg, sizeof(guest_msg))) + return -EFAULT; + + if (guest_msg.reserved) { + dev_dbg(vmw_zc_misc.this_device, + "reserved field must be zero: %u\n", + guest_msg.reserved); + return -EINVAL; + } + + switch (guest_msg.message_type) { + case VMW_ZC_MSG_USER_BUFFER: + buf =3D u64_to_user_ptr(guest_msg.u.data.buffer); + buf_len =3D guest_msg.u.data.buffer_length; + meta =3D u64_to_user_ptr(guest_msg.u.data.metadata); + meta_len =3D guest_msg.u.data.metadata_length; + ret =3D vmw_zc_send_user_buffer_msg(buf, buf_len, meta, meta_len); + break; + + case VMW_ZC_MSG_RAW: + ret =3D vmw_zc_send_raw_msg(guest_msg.u.raw_buffer.raw_buffer, + guest_msg.u.raw_buffer.raw_len); + break; + + default: + dev_dbg(vmw_zc_misc.this_device, + "unknown message type: %u\n", + guest_msg.message_type); + ret =3D -EINVAL; + break; + } + + return ret; +} + +static int __init vmw_zc_init(void) +{ + int ret; + + ret =3D vmw_zc_transport->init(); + if (ret) + return ret; + + ret =3D misc_register(&vmw_zc_misc); + if (ret) { + pr_err("failed to register misc device: %d\n", ret); + vmw_zc_transport->exit(); + return ret; + } + + return 0; +} + +static void __exit vmw_zc_exit(void) +{ + misc_deregister(&vmw_zc_misc); + vmw_zc_transport->exit(); +} + +module_init(vmw_zc_init); +module_exit(vmw_zc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Broadcom VMware zero-copy sync buffer sharing"); diff --git a/drivers/misc/vmw_zerocopy_priv.h b/drivers/misc/vmw_zerocopy_p= riv.h new file mode 100644 index 000000000000..f2de3ce9391a --- /dev/null +++ b/drivers/misc/vmw_zerocopy_priv.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2026 Broadcom. All Rights Reserved. The term + * "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + */ + +#ifndef _VMW_ZEROCOPY_PRIV_H_ +#define _VMW_ZEROCOPY_PRIV_H_ + +#include +#include +#include +#include +#include + +#define VMW_ZC_MAX_BUFFER_SIZE SZ_64K + +/* + * Worst-case pages spanned by a max-size buffer: the +1 covers a buffer w= hose + * start is not page aligned and therefore straddles one additional page. + */ +#define VMW_ZC_MAX_PAGES (DIV_ROUND_UP(VMW_ZC_MAX_BUFFER_SIZE, PAGE_SIZE) = + 1) + +/* Wire-format messages sent to the peer over the transport (driver privat= e). */ +struct vmw_zc_msg_unit { + u32 offset; + u32 length; + u32 num_pages; + u32 pad; + u64 page_pfns[VMW_ZC_MAX_PAGES]; +}; + +struct vmw_zc_user_buffer_pair { + struct vmw_zc_msg_unit data; + struct vmw_zc_msg_unit metadata; +}; + +struct vmw_zc_host_raw { + u8 raw[VMW_ZC_MAX_RAW_BUFFER_LEN]; +}; + +union vmw_zc_host_body { + struct vmw_zc_user_buffer_pair user_buf; + struct vmw_zc_host_raw raw; +}; + +struct vmw_zc_host_message { + u32 message_type; + u32 pad; + union vmw_zc_host_body body; +}; + +/* + * A transport delivers a filled-in message to its peer. The destination is + * owned entirely by the transport backend: userspace supplies no address = and + * cannot influence where a message is sent. + */ +struct vmw_zc_transport_ops { + int (*init)(void); + void (*exit)(void); + int (*send)(const struct vmw_zc_host_message *msg); +}; + +extern const struct vmw_zc_transport_ops vmw_zc_vmci_transport; + +#endif /* _VMW_ZEROCOPY_PRIV_H_ */ diff --git a/drivers/misc/vmw_zerocopy_vmci.c b/drivers/misc/vmw_zerocopy_v= mci.c new file mode 100644 index 000000000000..39aadc1afaad --- /dev/null +++ b/drivers/misc/vmw_zerocopy_vmci.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2026 Broadcom. All Rights Reserved. The term + * "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +#include "vmw_zerocopy_priv.h" + +/* + * On-wire layout: a VMCI datagram header immediately followed by our payl= oad. + * Built on the stack per send, so the send path holds no shared state and + * needs no lock. Must not be const: vmci_route() may rewrite src.context. + */ +struct vmw_zc_vmci_wire { + struct vmci_datagram hdr; + struct vmw_zc_host_message payload; +}; + +static struct vmci_handle vmw_zc_vmci_src_hdl; + +/* Driver is send-only; responses from the hypervisor are not expected. */ +static int vmw_zc_vmci_dgram_cb(void *cookie __always_unused, + struct vmci_datagram *dg __always_unused) +{ + return 0; +} + +/* + * Map a VMCI send failure to an errno, modelled on + * vmci_transport_error_to_vsock_error(). Distinguishing these matters mos= t for + * the unreachable cases: they are what a guest sees when the hypervisor h= as no + * listener on VMCI_VMWZC_DST_RID, which must not look like a transient fa= ilure. + */ +static int vmw_zc_vmci_errno(int vmci_error) +{ + switch (vmci_error) { + case VMCI_ERROR_INVALID_RESOURCE: + case VMCI_ERROR_NO_HANDLE: + case VMCI_ERROR_DST_UNREACHABLE: + return -EHOSTUNREACH; + case VMCI_ERROR_NO_MEM: + return -ENOMEM; + case VMCI_ERROR_NO_RESOURCES: + return -ENOBUFS; + case VMCI_ERROR_PAYLOAD_TOO_LARGE: + return -EMSGSIZE; + case VMCI_ERROR_NO_ACCESS: + case VMCI_ERROR_INVALID_PRIV: + return -EPERM; + case VMCI_ERROR_INVALID_ARGS: + return -EINVAL; + default: + return -EIO; + } +} + +static int vmw_zc_vmci_send(const struct vmw_zc_host_message *msg) +{ + struct vmw_zc_vmci_wire wire =3D { }; + int ret; + + BUILD_BUG_ON(offsetof(struct vmw_zc_vmci_wire, payload) !=3D + VMCI_DG_HEADERSIZE); + BUILD_BUG_ON(sizeof(wire) > VMCI_MAX_DG_SIZE); + + /* + * The destination is fixed by the host ABI (VMCI_VMWZC_DST_RID in + * VMCI's reserved hypervisor datagram range); userspace never selects + * it. @message_type in the payload distinguishes operations. + */ + wire.hdr.dst.context =3D VMCI_HYPERVISOR_CONTEXT_ID; + wire.hdr.dst.resource =3D VMCI_VMWZC_DST_RID; + wire.hdr.src =3D vmw_zc_vmci_src_hdl; + wire.hdr.payload_size =3D sizeof(wire.payload); + + /* + * memcpy, not struct assignment: the payload's union leaves its + * inactive tail bytes unspecified, and kernel stacks are recycled. + */ + memcpy(&wire.payload, msg, sizeof(wire.payload)); + + ret =3D vmci_datagram_send(&wire.hdr); + if (ret < 0) { + pr_err_ratelimited("failed to send VMCI datagram: %d\n", ret); + return vmw_zc_vmci_errno(ret); + } + return 0; +} + +static int vmw_zc_vmci_init(void) +{ + int ret; + + vmw_zc_vmci_src_hdl =3D VMCI_INVALID_HANDLE; + + ret =3D vmci_datagram_create_handle(VMCI_INVALID_ID, 0, + vmw_zc_vmci_dgram_cb, NULL, + &vmw_zc_vmci_src_hdl); + if (ret !=3D VMCI_SUCCESS) { + pr_err("failed to create VMCI datagram handle: %d\n", ret); + return -ENODEV; + } + + return 0; +} + +static void vmw_zc_vmci_exit(void) +{ + int ret; + + if (!vmci_handle_is_invalid(vmw_zc_vmci_src_hdl)) { + ret =3D vmci_datagram_destroy_handle(vmw_zc_vmci_src_hdl); + if (ret !=3D VMCI_SUCCESS) { + pr_err("failed to destroy VMCI datagram handle: %d\n", + ret); + } + } + vmw_zc_vmci_src_hdl =3D VMCI_INVALID_HANDLE; +} + +const struct vmw_zc_transport_ops vmw_zc_vmci_transport =3D { + .init =3D vmw_zc_vmci_init, + .exit =3D vmw_zc_vmci_exit, + .send =3D vmw_zc_vmci_send, +}; diff --git a/include/uapi/linux/vmw_zerocopy.h b/include/uapi/linux/vmw_zer= ocopy.h new file mode 100644 index 000000000000..0fa263870df1 --- /dev/null +++ b/include/uapi/linux/vmw_zerocopy.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */ +/* + * Copyright (c) 2026 Broadcom. All Rights Reserved. The term + * "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + */ + +#ifndef _UAPI_LINUX_VMW_ZEROCOPY_H_ +#define _UAPI_LINUX_VMW_ZEROCOPY_H_ + +#include +#include + +#define VMW_ZC_DEVICE_NAME "vmw_zc" +#define VMW_ZC_IOCTL_MAGIC 0xDC +/* + * Largest inline payload that keeps sizeof(struct vmw_zc_guest_message) + * at 48 bytes + */ +#define VMW_ZC_MAX_RAW_BUFFER_LEN 36 + +/* + * Used for sending user buffer. + * + * Pointers are __u64 so the struct layout is identical on 32-bit and 64-b= it + * userspace. The ioctl argument pointer itself is converted by + * compat_ptr_ioctl(); the driver uses u64_to_user_ptr() on these fields. + * + * Set buffer or metadata to 0 to indicate absence. + * At least one must be non-zero. + */ +struct vmw_zc_guest_data { + __u64 buffer; + __u64 metadata; + __u32 buffer_length; + __u32 metadata_length; +}; + +struct vmw_zc_guest_raw_buffer { + __u8 raw_buffer[VMW_ZC_MAX_RAW_BUFFER_LEN]; + __u32 raw_len; +}; + +/* + * @message_type: numeric values (see below). User-buffer transfer uses + * @u.data; small inline payload uses @u.raw_buffer. + * @reserved: must be zero. The destination is fixed by the driver and can= not + * be selected by userspace. + */ +#define VMW_ZC_MSG_USER_BUFFER 1 +#define VMW_ZC_MSG_RAW 2 + +struct vmw_zc_guest_message { + __u32 message_type; + __u32 reserved; + union { + struct vmw_zc_guest_data data; + struct vmw_zc_guest_raw_buffer raw_buffer; + } u; +}; + +#define VMW_ZC_IOCTL_NR_MSG 0x01 + +#define VMW_ZC_IOCTL_MSG \ + _IOW(VMW_ZC_IOCTL_MAGIC, VMW_ZC_IOCTL_NR_MSG, struct vmw_zc_guest_message) + +#endif /* _UAPI_LINUX_VMW_ZEROCOPY_H_ */ --=20 2.52.0 From nobody Fri Sep 25 09:19:46 2026 Received: from mail-vs1-f99.google.com (mail-vs1-f99.google.com [209.85.217.99]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5D6E33914EB for ; Mon, 14 Sep 2026 20:24:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.217.99 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789417463; cv=none; b=B3mUJL+xXx/SChmgNJy6zQPh0QWmgpAoydpgd35LALUPrDI69UTRHGYDGj2TrdJ+wgyrrYeHniMoNC5Qk8kWxN8a6lu/MERAx81qVMaqTtgosu1MrF9ukFWNCkBf8vc/BX/zRYDkxtf8qq6rSwuqjonm9eSUPghY1lOF6S5UgO8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789417463; c=relaxed/simple; bh=k2tzbk1Xu7br+97MZVzboFVQLhf+xwYbmmoNash5Lbs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LibGhbKILM8k4FCBteS3tZn5sASWBw82rxqLP5inHS4AqZF/ZkdloJS2bGjPnaAl1zKveJyYfx3LHElClqLaIEQy9ly/P3mTW3ngF9krIqQXPiWO0ylXFrZyqlgX94z2ZLSko1TEzfDE8RMBqAWTdh4vlDir4Jl6BPJNoX4K1bE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com; spf=fail smtp.mailfrom=broadcom.com; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b=Ox7RP5GA; arc=none smtp.client-ip=209.85.217.99 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=broadcom.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="Ox7RP5GA" Received: by mail-vs1-f99.google.com with SMTP id ada2fe7eead31-785073ad5ccso922192137.1 for ; Mon, 14 Sep 2026 13:24:21 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789417460; x=1790022260; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=Lw4cU/iYb1d+4k9XS51T95AvbCYV5HtwSci4L0F+IcE=; b=qJ4zx3tEsGa2n+XHrVTCrtCSuWY18rGLGzltSoM5Ft6l2yJyb6gsqgSuMfwzVQytn+ WE/6JofdwHAJgg0tumou2GTxmDFUwfA7rkQNcPB1U4B7kVsfVQUjuUam3clYgCW/sQqV 2PlPorknnSYV31w4R4h5k27aRCgPBaraMXv0QMfC+zemq+0ZbtQK1napx9NjMBRh3JzV 8YmITTodawmiJ/4ZzPusas+W/7DVuL0jjrTmIBKixyKJaKQNFZBcGnDqr8hAFTDV44ww iX0cCTir9ggzmA4k3RLa18fXIHIq76iwHEXxy4b5Z3bZHfAmGfjr66BK2Nh4AShzlm3m AqkA== X-Forwarded-Encrypted: i=1; AKwUvByjYmTAvtDbjD8WVAmu4Xn0gIm63MFdWf2ATCIu9dxEEPZV+0L6/4cimhwsOK7YrDeGKXKRLez1yImGv/4=@vger.kernel.org X-Gm-Message-State: AFuF++lR/R/uIu/6J4+JT/l5Ek9v1/xaWrNqRGb1UJRU++AgddYMgaWr CHgZ683++KqCtiMALHIvBc43AVPz6wSUau3rdEsC2hJXR8jfVNCpXkkqwCNUir7r0IsDOB4rg47 yA1k+5h19YuWxAJagMqrom2AJx2sc7OZLbQxmTowC75c5hHzjpPOd5L5o0sXB+6koh2fvUJKb2R iagtWPHQiiSH4KurSWlYrm6+XqZYwVZf1X+P3Tv0BuVXU65Y+13dB3cBoDKR/9wEXBth5ruBXOc kNKXGK4hAlkDFhwLO6xeg== X-Gm-Gg: AYBFou1vOrIMj3irQRLGPuuxMvSLbaSDExaY3O7H3++/H0tqNlsvWt/DS+LxD+qmoHL ndjbDr6g7rxTH1GpAXo5JlBsn+d5xlxATE6m46NZ9zV8rktIGTW8/mov0DVAKLpgf/eg8Ty9HO/ qtD+v9ivu/li6tUDOQjXeNEzBemQ+xQrIl0LG+6TDU+/VmWEtKOVUu6bt99Kh/+Zbj9qYPqGn4z juaM/HetqJtwTpAlfkqSiahcAKWJjoMgie0lT/TSaqEKTTpRdmz7Y0HJB3Tsve3hwDCyNPqjvG5 tWz+zGI91k9hgH5S3xnLQ9h40EiH639IIRZjoeFAAV+ajIL1pJOnDdQFCFV3CCFERimwrcPdd7a BGrgLqMuAVznvxqzNrE/l6HPpxg+XufcWZDPSSq6wzqXMVcAxmNgtGaT6qqN3kw== X-Received: by 2002:a05:6102:510b:b0:784:b9ec:913d with SMTP id ada2fe7eead31-79b5acba6b0mr2198372137.8.1789417460017; Mon, 14 Sep 2026 13:24:20 -0700 (PDT) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com ([144.49.247.127]) by smtp-relay.gmail.com with ESMTPS id ada2fe7eead31-7927dab913asm203656137.14.2026.09.14.13.24.19 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 14 Sep 2026 13:24:20 -0700 (PDT) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-oa1-f69.google.com with SMTP id 586e51a60fabf-47d75bcf3ebso3480088fac.0 for ; Mon, 14 Sep 2026 13:24:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1789417459; x=1790022259; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Lw4cU/iYb1d+4k9XS51T95AvbCYV5HtwSci4L0F+IcE=; b=Ox7RP5GA1kaNnqbnJyMQpVpqIbSLW5KM5CZ/7pfC+R4XLd9LAuApy2yxuotxRV7pSz Yo401mUcfLZtrRR8wr0zTULlYaUs/9hXg4pES+qV8bWlkP7X1PPKjbdXQobXnk1jousa 79Ii2aoIzK8Sk4Y4Eogw4q9DkCcKgHr5KQtLA= X-Forwarded-Encrypted: i=1; AKwUvBxsRLRPCNSQE0pB6BUoVOL8MQumoGO4PLFZzzDFh2KNLqT6LWtlqXF/LPVBGqGAc7ku+qK9/xntxDK51NA=@vger.kernel.org X-Received: by 2002:a05:6870:44b:b0:47b:dbb4:7cbb with SMTP id 586e51a60fabf-481f9b10f9fmr4289079fac.14.1789417458745; Mon, 14 Sep 2026 13:24:18 -0700 (PDT) X-Received: by 2002:a05:6870:44b:b0:47b:dbb4:7cbb with SMTP id 586e51a60fabf-481f9b10f9fmr4289044fac.14.1789417458237; Mon, 14 Sep 2026 13:24:18 -0700 (PDT) Received: from lvn-dbc2489.lvn.broadcom.net ([192.19.161.250]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-47df8699bc6sm11623741fac.3.2026.09.14.13.24.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 13:24:17 -0700 (PDT) From: Rishi Chhibber To: gregkh@linuxfoundation.org, arnd@arndb.de Cc: bryan-bt.tan@broadcom.com, vishnu.dasa@broadcom.com, corbet@lwn.net, skhan@linuxfoundation.org, shuah@kernel.org, rdunlap@infradead.org, bcm-kernel-feedback-list@broadcom.com, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, ajay.kaher@broadcom.com, alexey.makhalov@broadcom.com, vamsi-krishna.brahmajosyula@broadcom.com, yin.ding@broadcom.com, tapas.kundu@broadcom.com, Rishi Chhibber Subject: [PATCH v3 3/4] Documentation: misc: Add vmw_zerocopy driver documentation Date: Mon, 14 Sep 2026 13:22:08 -0700 Message-ID: <714b2c18a9f4ad7a4adc927941965ef45e8438c7.1789413109.git.rishi.chhibber@broadcom.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-DetectorID-Processed: b00c1d49-9d2e-4205-b15f-d015386d3d5e Content-Type: text/plain; charset="utf-8" Summary of changes: - Add Documentation/misc-devices/vmw_zerocopy.rst describing the device node, the ioctl interface, the message types and the buffer limits - Link it from Documentation/misc-devices/index.rst Document the userspace interface of the vmw_zerocopy driver added earlier in this series: the /dev/vmw_zc device node, the VMW_ZC_IOCTL_MSG ioctl and its message types, the data and metadata size limits, and an example call sequence. The prose also covers the parts of the design that are not apparent from the interface alone: how a PFN list replaces a data copy, the metadata feedback path and why those pages need different release handling from the data pages, the atomic submission semantics of placing both PFN lists in a single datagram, the transport abstraction, and why the destination resource id is owned by the kernel rather than selectable by userspace. Signed-off-by: Rishi Chhibber Reviewed-by: Alexey Makhalov Reviewed-by: Vishnu Dasa --- Documentation/misc-devices/index.rst | 1 + Documentation/misc-devices/vmw_zerocopy.rst | 278 ++++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 Documentation/misc-devices/vmw_zerocopy.rst diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devi= ces/index.rst index f911edaecbfa..8d1687a2d566 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -27,4 +27,5 @@ fit into other categories. spear-pcie-gadget tps6594-pfsm uacce + vmw_zerocopy xilinx_sdfec diff --git a/Documentation/misc-devices/vmw_zerocopy.rst b/Documentation/mi= sc-devices/vmw_zerocopy.rst new file mode 100644 index 000000000000..80a6277acf28 --- /dev/null +++ b/Documentation/misc-devices/vmw_zerocopy.rst @@ -0,0 +1,278 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +VMware Zero-Copy Buffer Sharing Driver +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Overview +=3D=3D=3D=3D=3D=3D=3D=3D + +The VMware zero-copy driver (``vmw_zerocopy``) provides a misc character +device at ``/dev/vmw_zc`` that allows guest userspace to share memory buff= ers +with a VMware hypervisor-side peer without copying the payload through a +kernel bounce buffer. + +The driver's responsibilities are strictly bounded: + +- Pin the caller's user pages with ``pin_user_pages_fast()``. +- Collect the physical page frame numbers (PFNs) of those pages. +- Transmit the PFN list to the hypervisor peer through the driver's + transport backend (currently VMCI; see `Transport Abstraction`_). +- Unpin the pages when the ioctl returns. + +The hypervisor reads the payload directly from the guest's physical frames. +No data is copied into or out of kernel memory. + + +How Zero Copy Works +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +A conventional driver copies application data into a kernel buffer and then +sends that buffer to the device. This driver does not. + +When userspace calls ``VMW_ZC_IOCTL_MSG`` with a ``VMW_ZC_MSG_USER_BUFFER`` +message, the kernel: + +1. Calls ``pin_user_pages_fast()`` to pin the data and metadata pages in + place, preventing them from being swapped or moved for the duration of + the ioctl. +2. Iterates over the pinned pages and records each page's PFN using + ``page_to_pfn()``. +3. Packs the PFN list into a ``struct vmw_zc_host_message`` and hands it to + the transport backend for delivery to the hypervisor peer (currently + VMCI's ``vmci_datagram_send()``). +4. Calls ``unpin_user_pages()`` before returning. + +The hypervisor receives the datagram, maps the listed guest-physical frames +directly, and accesses the buffer contents without any copy traversing the +guest kernel. The guest kernel never touches the payload data itself. + + +Metadata Feedback Path +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Each ``VMW_ZC_MSG_USER_BUFFER`` call may supply two separate buffers: + +- **data buffer** - the payload the hypervisor will read. Pages are pinned + with ``gup_flags =3D 0`` (read-only from the caller's perspective). +- **metadata buffer** - a control region (up to 64 KiB) the hypervisor + writes into. Pages are pinned with ``FOLL_WRITE`` so the hypervisor can + store per-operation results directly in the caller's own memory. + +Both PFN lists travel in a single VMCI datagram. The hypervisor, while th= ose +pages are still pinned, writes per-operation information - such as complet= ion +status, byte counts, or application-level result codes - directly into the +metadata pages. + +Because the metadata pages are the same physical pages that userspace mapp= ed, +userspace can read the hypervisor's response immediately after the ioctl +returns by reading its own buffer. No additional system call is required = to +retrieve the result. + +Key properties of this feedback path: + +- **Per-call**: a fresh metadata region is provided with each ioctl, so + results from one call do not interfere with another. +- **Synchronous**: the result is present in the metadata buffer when the + ioctl returns; no polling or waiting is required. +- **In-place**: the hypervisor writes into the caller's own pinned pages; + the result does not pass through any intermediate kernel buffer. +- **Rich**: up to 64 KiB of arbitrary per-operation result data per call. + + +Atomic Submission Semantics +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D + +Both the data PFN list and the metadata PFN list are placed in a single +``struct vmw_zc_host_message`` and delivered in one transport ``send()`` +call (currently backed by a single ``vmci_datagram_send()``). The +hypervisor receives the complete bundle atomically. There is no state held +between ioctl calls: if the send fails, nothing has been committed on the +hypervisor side. This makes error recovery straightforward for the caller. + + +Transport Abstraction +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The driver is split along a small internal interface so that VMCI is a +swappable backend rather than something the ioctl path depends on directly: + +- ``vmw_zerocopy_core.c`` owns the misc device, the ioctl, and user page + pinning. It builds a ``struct vmw_zc_host_message`` on the stack and + hands it to a transport for delivery. It contains no VMCI-specific code. +- ``vmw_zerocopy_vmci.c`` implements delivery over VMCI: creating the + driver's VMCI datagram handle, maintaining the per-peer datagram buffers + described under `Constraints`_, and calling ``vmci_datagram_send()``. + +The two are joined by ``struct vmw_zc_transport_ops``, defined in the +driver-private ``vmw_zerocopy_priv.h``:: + + struct vmw_zc_transport_ops { + int (*init)(void); + void (*exit)(void); + int (*send)(const struct vmw_zc_host_message *msg); + }; + +VMCI is currently the only transport, selected at compile time with +``vmw_zc_transport =3D &vmw_zc_vmci_transport`` in ``vmw_zerocopy_core.c``. +The destination is owned entirely by the transport backend, so ``send()`` = takes +no address argument. Adding a second transport means implementing this +interface in a new source file and pointing ``vmw_zc_transport`` at it - t= he +ioctl, pinning, and message-building code do not change. + + +Use Cases +=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This driver is suited to workloads where: + +- A guest application needs to hand large buffers to a VMware hypervisor + service without incurring a kernel-to-kernel copy of the payload. +- Per-operation completion feedback (status, byte count, result code) is + required synchronously with the send, without a separate receive call. +- The metadata region is bounded (<=3D 64 KiB) and the response latency mu= st be + bounded by the ioctl round-trip rather than by a polling interval. + +Examples include guest-side offload of data transformation, checksum, or +inspection workloads where the hypervisor peer processes each buffer and +reports the outcome directly into the caller's metadata page. + + +Userspace API +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Device +------ + +The driver registers a misc character device:: + + /dev/vmw_zc + +The device is created with mode ``0644`` so that unprivileged guest +userspace can open it without additional privilege. + +ioctl +----- + +All operations use a single ioctl:: + + ioctl(fd, VMW_ZC_IOCTL_MSG, &msg) + +where ``msg`` is a ``struct vmw_zc_guest_message`` defined in +``include/uapi/linux/vmw_zerocopy.h``. + +Addressing the peer +------------------- + +Userspace does not address the peer. The destination is a compile-time +constant owned by the transport backend, and there is no initialisation ca= ll +and no per-message address field. + +This is deliberate. The destination is a VMCI resource ID in the hypervis= or +context, and that namespace belongs to the platform: low IDs are the +hypervisor's own control entry points. A device node that unprivileged +userspace can open must therefore not let userspace name a destination, or= it +becomes an unfiltered writer onto the hypervisor's control namespace. +``msg.reserved`` exists only to keep the structure layout fixed and must be +zero; a non-zero value returns ``-EINVAL``. + +Message types +------------- + +``VMW_ZC_MSG_USER_BUFFER`` + Transfer a buffer, with optional metadata feedback. Fill + ``msg.u.data`` as follows: + + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Field Meaning + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + ``buffer`` ``__u64`` userspace address of the data buffer; + 0 if no data buffer. + ``buffer_length`` Length in bytes; 1-65536 (64 KiB maximum). + ``metadata`` ``__u64`` userspace address of the metadata buffe= r; + 0 if no metadata buffer. + ``metadata_length`` Length in bytes; 1-65536 (64 KiB maximum). + =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + + At least one of ``buffer`` or ``metadata`` must be non-zero. + The metadata buffer must remain mapped for the duration of the ioctl; the + hypervisor may write into it at any point while the call is in progress. + +``VMW_ZC_MSG_RAW`` + Send a small inline payload (<=3D 36 bytes) to the peer without pinning = any + user pages. Fill ``msg.u.raw_buffer.raw_buffer`` with the payload and + set ``msg.u.raw_buffer.raw_len`` to the payload length. Useful for + lightweight control or signaling messages. + +Pointer fields (``buffer``, ``metadata``) are declared as ``__u64`` so that +``struct vmw_zc_guest_message`` has the same layout on 32-bit and 64-bit +userspace. The argument pointer itself still needs conversion for 32-bit +callers, so ``.compat_ioctl`` is set to ``compat_ptr_ioctl``. + +Example call sequence +--------------------- + +The following pseudo-code illustrates the typical usage pattern:: + + /* Step 1: open the device */ + fd =3D open("/dev/vmw_zc", O_RDWR); + + /* Step 2: allocate data and metadata buffers */ + void *data =3D mmap(NULL, DATA_SIZE, PROT_READ, ..= .); + void *metadata =3D mmap(NULL, METADATA_SIZE, PROT_READ | PROT_WRITE,..= .); + /* fill data buffer with payload */ + + /* Step 3: transfer the buffer and wait for metadata feedback. + * There is no destination to supply; the driver owns it. + */ + struct vmw_zc_guest_message xfer_msg =3D { + .message_type =3D VMW_ZC_MSG_USER_BUFFER, + .u.data =3D { + .buffer =3D (uint64_t)(uintptr_t)data, + .buffer_length =3D DATA_SIZE, + .metadata =3D (uint64_t)(uintptr_t)metadata, + .metadata_length =3D METADATA_SIZE, + }, + }; + ioctl(fd, VMW_ZC_IOCTL_MSG, &xfer_msg); + + /* Step 4: read the result - no extra syscall needed */ + struct my_result *res =3D (struct my_result *)metadata; + if (res->status =3D=3D 0) + /* success */; + + +Constraints +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +**One destination, fixed by the driver.** +The peer is not selectable by userspace; see "Addressing the peer" above. +The send path builds its datagram on the stack per call, so it performs no +allocation, holds no driver lock, and has no shared mutable state. Concur= rent +senders are serialised only where the VMCI transport itself serialises the= m. + +**Send-only.** +The driver transmits PFN descriptors to the hypervisor; it does not receive +datagrams. Hypervisor responses are delivered through the metadata writeb= ack +path described above, not through a kernel receive queue. + +**Buffer size limits.** +Data and metadata buffers are both capped at 64 KiB (``SZ_64K``). These l= imits +bound the worst-case VMCI datagram size and the number of pages that must +remain pinned during the ioctl. + +**Inline raw payload limit.** +The ``VMW_ZC_MSG_RAW`` message carries at most 36 bytes +(``VMW_ZC_MAX_RAW_BUFFER_LEN``). + +**Incompatible with encrypted guest memory.** +The driver's correctness depends on the hypervisor being able to read and +write guest physical pages. Hardware memory encryption (AMD SEV-SNP, Intel +TDX) intentionally prevents this. The Kconfig dependency +``depends on !X86_MEM_ENCRYPT`` enforces this constraint at build time and +prevents the module from being enabled in encrypted-memory guests. + +**x86 only.** +The driver depends on ``CONFIG_X86`` and ``CONFIG_HYPERVISOR_GUEST``. Its +current transport backend uses ``VMWARE_VMCI`` (see `Transport +Abstraction`_), which is an x86 VMware platform interface. --=20 2.52.0 From nobody Fri Sep 25 09:19:46 2026 Received: from mail-qv1-f100.google.com (mail-qv1-f100.google.com [209.85.219.100]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 95311479887 for ; Mon, 14 Sep 2026 20:24:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.100 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789417466; cv=none; b=MTZ0aTsQuLjFGsKTkbY7RQGthezksVc3yD8Nh2jrtAQ/7nVRwXNpNf4M9fGCm1XLbdK/N4WjBjQ5Pn8rEJp5vZ/Wwlkc1f5VIniT9fmW6ku18NeA5choZUcSTMSVwI5Vxrhcp+OgXfRepLmI2dYhhRnvySuxyrx3dsCT+z/20+A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789417466; c=relaxed/simple; bh=QzGyE3gc3NE4McPOtuP5S55HZ8A8IfEQPntOV+MpgGA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Y8NHC4hqWQOoWZ9Su/wC7GYJrqNtgm9U3h5o7z4nV3A7nYYM8vvPo+aqkulCHf9D72PIr3YkCIVQglYqFiupOL3vZRNXVhM5ybTIAYxXQy+9sIm6m0evfFsryDB/wiekkLVkbtyTws7IkCArR7PYsARoGuOeTiaT3nyiHkSEgVI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com; spf=fail smtp.mailfrom=broadcom.com; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b=OkMlmVxB; arc=none smtp.client-ip=209.85.219.100 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=broadcom.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="OkMlmVxB" Received: by mail-qv1-f100.google.com with SMTP id 6a1803df08f44-9106fad6f0cso8812216d6.2 for ; Mon, 14 Sep 2026 13:24:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789417462; x=1790022262; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=9PdHc/PVNJgEKpmU97s5aFFCrW71lWLYc+Sp0PVMH3I=; b=jhHygynAKjShFZCs2VMfYnQ4s4sp12e8jYlRbh1VPOiRFwvvsOlzhXW/eWLIqnBERA 6B7KtfZm3GFVYJq8/HGX1RkCRX8wVn1108Xrxsqb+TXGl9ATeGMJfZdRvnAaO1fCYHRF oau1CGkfUbb2BL+G8ZVvDzSEptBx5aaT7nrx9HQPQvB2MnHWLvKzywJegiutfvC+YDq+ 9i1NiEcF2I2Yjg7S9iVBnfFBUuqZjjRoNV7zN7OPR5GgxlFqJygyjEmwfo/F6tdwDCwV yyAB1DvhZM0hYDY4bllwme8xLfYMasYu9TN8X1cCi3MfVM4P2mXgPydQwu6x4da6d5t1 JOPQ== X-Forwarded-Encrypted: i=1; AKwUvBwoVx6g9aPVsbgGYSN3DXoZ2kl34w6XnG6XRE9V9lR+5L45S4x57kLQdjeco0+XhyLS+n+yTe9TzGmNLtg=@vger.kernel.org X-Gm-Message-State: AFuF++n+BaaPq498uvpNc0Lb8sx7FqLesMnq/QaFTNe7Q/IO1nGQc7W+ XKWRWEvbOkGTyBTYsJawuXRraePGeRuuKatXxRSTOMIhXPN1qzufAPpamjg2jcOiFPj3rxI/wJG S9gWaW/XIXcAKeGdHij2lSqL6lYfUKNuZmQNJfWf3x5JPjpp6mvOx1+B3lBlroWmWawIyi3EGtm imosjg7WJi3UzJBUR+3stOh/7KpIUIUBjE6SmqarCWPvaCxK5cxtrl1+zlmhZNiX1kC1wXieS9p jpR9xBpWlAPzxTKtyMXJA== X-Gm-Gg: AYBFou2i7M2ZRwnybOd4m3Zt6RWriY/cRJ2zqe5t8ussZ/Lr6wVGGic9VMKI9fxItge 4mMytDdXen6oWlza00KKx0ILW2l0cZkujZtkPHchmA7CRfm+ZjpfKIQCBzeRyJi73Tj0pTM8dO6 2v7qlcvFuF20bloQxOFwajJ9k61sdFLZq5FZgNNNGNOmya4s8eIeDcq18lCaKUauZnLrGnuHR/O 0W0tvCXOlGAtuBasVf6lT2xGQmEn6DXZgifvP16ARiLrjFkmdj2wKJONQiOjKy0Y6YbpfQRCfpy tXjPMGsyKyXGwOCWEA7RF7Tt/1/eOvueeDg8SzwBzYGkLfPsOLMHPxmAKEsKJ4nU7P+RULqDh2u d+k3JqqM890Ejssw+EPLrNcoyxnhbY5gTopa/BFjDBfz9yvTOen9oY5wFUs3Q896sQgjpaJe0zr p0gSK3GOvQyUPeSmx/xpavowZF9bkwThiwiGKHca8s X-Received: by 2002:a05:622a:1904:b0:51c:84f0:d903 with SMTP id d75a77b69052e-5310cf4eb51mr65348441cf.17.1789417462336; Mon, 14 Sep 2026 13:24:22 -0700 (PDT) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-125.dlp.protect.broadcom.com. [144.49.247.125]) by smtp-relay.gmail.com with ESMTPS id d75a77b69052e-530ca5134e0sm1443431cf.19.2026.09.14.13.24.22 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 14 Sep 2026 13:24:22 -0700 (PDT) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-oi1-f197.google.com with SMTP id 5614622812f47-4c7f887ac6bso1276123b6e.3 for ; Mon, 14 Sep 2026 13:24:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1789417461; x=1790022261; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=9PdHc/PVNJgEKpmU97s5aFFCrW71lWLYc+Sp0PVMH3I=; b=OkMlmVxBDf6ujDO7831RpnCzvz4ocnitJ/JT1sCzf18S/H6QMJj2dMMnh/GVN4HAub gTTvmONnAb5EV7zXI8HCtLruWwjzBV/BWfkvxfFnb1slZ8O4TnqzWZnulvtFp0sg/C8g +qhcyxS/P/t0NRGAWOEJPZCBIBM6RbtJq9uqQ= X-Forwarded-Encrypted: i=1; AKwUvByX0C4U35SHVUQeytHI3E5b9D1zXlLiyJk2Nf/KC8CVP7CfQ6JqzdVgBQh8lJjUtvQrPtDIFDmOfAEYYP4=@vger.kernel.org X-Received: by 2002:a05:6820:1f0f:b0:6b1:b375:481 with SMTP id 006d021491bc7-6c53bf22621mr4454250eaf.0.1789417461198; Mon, 14 Sep 2026 13:24:21 -0700 (PDT) X-Received: by 2002:a05:6820:1f0f:b0:6b1:b375:481 with SMTP id 006d021491bc7-6c53bf22621mr4454212eaf.0.1789417460636; Mon, 14 Sep 2026 13:24:20 -0700 (PDT) Received: from lvn-dbc2489.lvn.broadcom.net ([192.19.161.250]) by smtp.gmail.com with ESMTPSA id 586e51a60fabf-47df8699bc6sm11623741fac.3.2026.09.14.13.24.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 13:24:19 -0700 (PDT) From: Rishi Chhibber To: gregkh@linuxfoundation.org, arnd@arndb.de Cc: bryan-bt.tan@broadcom.com, vishnu.dasa@broadcom.com, corbet@lwn.net, skhan@linuxfoundation.org, shuah@kernel.org, rdunlap@infradead.org, bcm-kernel-feedback-list@broadcom.com, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, ajay.kaher@broadcom.com, alexey.makhalov@broadcom.com, vamsi-krishna.brahmajosyula@broadcom.com, yin.ding@broadcom.com, tapas.kundu@broadcom.com, Rishi Chhibber Subject: [PATCH v3 4/4] selftests: misc: Add vmw_zerocopy selftest Date: Mon, 14 Sep 2026 13:22:09 -0700 Message-ID: X-Mailer: git-send-email 2.52.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-DetectorID-Processed: b00c1d49-9d2e-4205-b15f-d015386d3d5e Content-Type: text/plain; charset="utf-8" Summary of changes: - Add tools/testing/selftests/drivers/misc/vmw_zerocopy: a kselftest_harness test covering the ioctl input-validation paths, plus its Makefile and config fragment - Add the target to tools/testing/selftests/Makefile Cover the input-validation paths of the vmw_zerocopy ioctl added earlier in this series: an unknown ioctl number, a bad message pointer, an unknown message type, a non-zero reserved word, neither buffer supplied, zero-length and oversized data and metadata buffers, a wrapping address+length, a wrapping PAGE_ALIGN() of the end address, an unmapped buffer, and zero-length and oversized raw payloads. These are all rejected before any datagram is sent, so they need no hypervisor peer. Two further tests submit a well-formed message and assert only that any failure is not a validation error, which holds whether or not a peer is listening; they also check that repeated sends do not depend on per-call setup surviving. The whole test therefore runs on any guest where the module loads, and skips cleanly when /dev/vmw_zc is absent so it does not fail on kernels built without CONFIG_VMW_ZC. Signed-off-by: Rishi Chhibber Reviewed-by: Alexey Makhalov Reviewed-by: Vishnu Dasa --- tools/testing/selftests/Makefile | 1 + .../drivers/misc/vmw_zerocopy/.gitignore | 1 + .../drivers/misc/vmw_zerocopy/Makefile | 20 ++ .../drivers/misc/vmw_zerocopy/config | 2 + .../misc/vmw_zerocopy/test_vmw_zerocopy.c | 276 ++++++++++++++++++ 5 files changed, 300 insertions(+) create mode 100644 tools/testing/selftests/drivers/misc/vmw_zerocopy/.giti= gnore create mode 100644 tools/testing/selftests/drivers/misc/vmw_zerocopy/Makef= ile create mode 100644 tools/testing/selftests/drivers/misc/vmw_zerocopy/config create mode 100644 tools/testing/selftests/drivers/misc/vmw_zerocopy/test_= vmw_zerocopy.c diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Mak= efile index 2d960626750e..325723e92bf3 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -20,6 +20,7 @@ TARGETS +=3D devices/error_logs TARGETS +=3D devices/probe TARGETS +=3D dmabuf-heaps TARGETS +=3D drivers/dma-buf +TARGETS +=3D drivers/misc/vmw_zerocopy TARGETS +=3D drivers/ntsync TARGETS +=3D drivers/s390x/uvdevice TARGETS +=3D drivers/net diff --git a/tools/testing/selftests/drivers/misc/vmw_zerocopy/.gitignore b= /tools/testing/selftests/drivers/misc/vmw_zerocopy/.gitignore new file mode 100644 index 000000000000..68941a8c0553 --- /dev/null +++ b/tools/testing/selftests/drivers/misc/vmw_zerocopy/.gitignore @@ -0,0 +1 @@ +test_vmw_zerocopy diff --git a/tools/testing/selftests/drivers/misc/vmw_zerocopy/Makefile b/t= ools/testing/selftests/drivers/misc/vmw_zerocopy/Makefile new file mode 100644 index 000000000000..195826f72f9c --- /dev/null +++ b/tools/testing/selftests/drivers/misc/vmw_zerocopy/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +include ../../../../../build/Build.include + +UNAME_M :=3D $(shell uname -m) + +ifeq ($(filter $(UNAME_M),x86_64 i686 i386),) +nothing: +.PHONY: all clean run_tests install +.SILENT: +else + +TEST_GEN_PROGS :=3D test_vmw_zerocopy + +top_srcdir ?=3D ../../../../../.. + +CFLAGS +=3D -Wall -Werror $(KHDR_INCLUDES) + +include ../../../lib.mk + +endif diff --git a/tools/testing/selftests/drivers/misc/vmw_zerocopy/config b/too= ls/testing/selftests/drivers/misc/vmw_zerocopy/config new file mode 100644 index 000000000000..03e4a430c5ff --- /dev/null +++ b/tools/testing/selftests/drivers/misc/vmw_zerocopy/config @@ -0,0 +1,2 @@ +CONFIG_VMWARE_VMCI=3Dm +CONFIG_VMW_ZC=3Dm diff --git a/tools/testing/selftests/drivers/misc/vmw_zerocopy/test_vmw_zer= ocopy.c b/tools/testing/selftests/drivers/misc/vmw_zerocopy/test_vmw_zeroco= py.c new file mode 100644 index 000000000000..af8035c4fa0f --- /dev/null +++ b/tools/testing/selftests/drivers/misc/vmw_zerocopy/test_vmw_zerocopy.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * selftest for the VMware zero-copy buffer sharing UAPI + * + * Copyright (c) 2026 Broadcom. All Rights Reserved. The term + * "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * Every input check in the driver runs before the message reaches the + * transport, so all of the tests below are meaningful without a hypervisor + * peer listening: they assert that bad input is rejected with the documen= ted + * errno. Tests that would require a live peer only assert "not one of the + * input-validation errnos", since the transport result depends on the hos= t. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../../../kselftest_harness.h" + +#define VMW_ZC_PATH "/dev/" VMW_ZC_DEVICE_NAME + +/* Driver-private, but fixed by the UAPI's documented buffer limits. */ +#define VMW_ZC_TEST_MAX_BUFFER 65536 + +FIXTURE(vmw_zc) { + int fd; + void *data; + void *metadata; + size_t page_size; +}; + +FIXTURE_SETUP(vmw_zc) +{ + self->page_size =3D (size_t)getpagesize(); + + self->fd =3D open(VMW_ZC_PATH, O_RDWR); + if (self->fd < 0) + SKIP(return, "cannot open %s: %s", VMW_ZC_PATH, + strerror(errno)); + + self->data =3D mmap(NULL, self->page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, self->data); + + self->metadata =3D mmap(NULL, self->page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, self->metadata); + + memset(self->data, 0xa5, self->page_size); +} + +FIXTURE_TEARDOWN(vmw_zc) +{ + if (self->data) + munmap(self->data, self->page_size); + if (self->metadata) + munmap(self->metadata, self->page_size); + if (self->fd >=3D 0) + close(self->fd); +} + +/* An unknown ioctl number must be rejected, not silently accepted. */ +TEST_F(vmw_zc, unknown_ioctl) +{ + struct vmw_zc_guest_message msg =3D { }; + + EXPECT_EQ(-1, ioctl(self->fd, _IOW(VMW_ZC_IOCTL_MAGIC, 0x7f, + struct vmw_zc_guest_message), &msg)); + EXPECT_EQ(ENOTTY, errno); +} + +TEST_F(vmw_zc, bad_message_pointer) +{ + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, NULL)); + EXPECT_EQ(EFAULT, errno); +} + +TEST_F(vmw_zc, unknown_message_type) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D 0xffff; + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EINVAL, errno); +} + +/* + * The destination is owned by the kernel: @reserved is not an address and= a + * caller that treats it as one (e.g. a binary built against the older hea= der + * where this word was peer_id) must fail loudly rather than be misrouted. + */ +TEST_F(vmw_zc, reserved_must_be_zero) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + msg.reserved =3D 1; + msg.u.data.buffer =3D (__u64)(uintptr_t)self->data; + msg.u.data.buffer_length =3D 64; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EINVAL, errno); +} + +TEST_F(vmw_zc, neither_buffer_nor_metadata) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EINVAL, errno); +} + +TEST_F(vmw_zc, zero_length_buffer) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + msg.u.data.buffer =3D (__u64)(uintptr_t)self->data; + msg.u.data.buffer_length =3D 0; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EINVAL, errno); +} + +TEST_F(vmw_zc, oversized_buffer) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + msg.u.data.buffer =3D (__u64)(uintptr_t)self->data; + msg.u.data.buffer_length =3D VMW_ZC_TEST_MAX_BUFFER + 1; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EINVAL, errno); +} + +TEST_F(vmw_zc, oversized_metadata) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + msg.u.data.metadata =3D (__u64)(uintptr_t)self->metadata; + msg.u.data.metadata_length =3D VMW_ZC_TEST_MAX_BUFFER + 1; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EINVAL, errno); +} + +/* + * A near-top address must be rejected by the range check before any page-= count + * arithmetic runs, whether it wraps on start + length or only on the + * subsequent page alignment. + */ +TEST_F(vmw_zc, address_length_overflow) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + msg.u.data.buffer =3D ~(__u64)0 - 15; + msg.u.data.buffer_length =3D 4096; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EFAULT, errno); +} + +/* + * The page-alignment-only wrap: start + length does not overflow, but rou= nding + * the end up to a page boundary would, which previously yielded nr_pages = =3D=3D 1. + */ +TEST_F(vmw_zc, address_page_align_overflow) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + msg.u.data.buffer =3D ~(__u64)0 - 0x7ff; + msg.u.data.buffer_length =3D 0x800; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EFAULT, errno); +} + +TEST_F(vmw_zc, unmapped_buffer) +{ + struct vmw_zc_guest_message msg =3D { }; + void *gap; + + gap =3D mmap(NULL, self->page_size, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, gap); + ASSERT_EQ(0, munmap(gap, self->page_size)); + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + msg.u.data.buffer =3D (__u64)(uintptr_t)gap; + msg.u.data.buffer_length =3D 64; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EFAULT, errno); +} + +TEST_F(vmw_zc, zero_length_raw) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D VMW_ZC_MSG_RAW; + msg.u.raw_buffer.raw_len =3D 0; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EINVAL, errno); +} + +TEST_F(vmw_zc, oversized_raw) +{ + struct vmw_zc_guest_message msg =3D { }; + + msg.message_type =3D VMW_ZC_MSG_RAW; + msg.u.raw_buffer.raw_len =3D VMW_ZC_MAX_RAW_BUFFER_LEN + 1; + + EXPECT_EQ(-1, ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg)); + EXPECT_EQ(EINVAL, errno); +} + +/* + * A well-formed send passes every input check, so it must not fail with o= ne + * of the validation errnos. Whether it ultimately succeeds depends on a p= eer + * being present, which this test cannot assume. + */ +TEST_F(vmw_zc, well_formed_send_passes_validation) +{ + struct vmw_zc_guest_message msg =3D { }; + int rc; + + msg.message_type =3D VMW_ZC_MSG_USER_BUFFER; + msg.u.data.buffer =3D (__u64)(uintptr_t)self->data; + msg.u.data.buffer_length =3D 64; + msg.u.data.metadata =3D (__u64)(uintptr_t)self->metadata; + msg.u.data.metadata_length =3D 64; + + rc =3D ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg); + if (rc < 0) { + EXPECT_NE(EINVAL, errno); + EXPECT_NE(EFAULT, errno); + EXPECT_NE(ENOTTY, errno); + TH_LOG("send returned %s; a hypervisor peer may not be present", + strerror(errno)); + } +} + +/* Repeated sends must not depend on any per-call setup surviving. */ +TEST_F(vmw_zc, repeated_raw_sends) +{ + struct vmw_zc_guest_message msg =3D { }; + int i; + + msg.message_type =3D VMW_ZC_MSG_RAW; + msg.u.raw_buffer.raw_len =3D VMW_ZC_MAX_RAW_BUFFER_LEN; + memset(msg.u.raw_buffer.raw_buffer, 0x5a, + sizeof(msg.u.raw_buffer.raw_buffer)); + + for (i =3D 0; i < 16; i++) { + if (ioctl(self->fd, VMW_ZC_IOCTL_MSG, &msg) < 0) { + EXPECT_NE(EINVAL, errno); + EXPECT_NE(ENOTTY, errno); + } + } +} + +TEST_HARNESS_MAIN --=20 2.52.0