From nobody Sun Jun 14 00:17:47 2026 Received: from mail.nessuent.net (mail.nessuent.net [188.245.177.90]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 428FF3E92B3; Tue, 5 May 2026 08:14:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=188.245.177.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968860; cv=none; b=E72O+1ToLp/J1hniA8tNKviDWUt2iiLH9XiInlONDmDeaz5PGhrMVQGhVpSaPALYLSw82pb7Zb8Oge6kWv50w8P6Q7Whus0wrUOiNAglYkaAJPTGLPQwUKCAs7U8OHy9nPdGFLOBX96MN33gFDSgRr7tB7lTeJWiX1pLwjS5Hd8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968860; c=relaxed/simple; bh=lunnIEDIwUnQNvPG0VVtgNP08wmfg3dV+L6Z49Gti7M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=W8zcsvcyonZt6n1kDHk0ck9mLIhR098MoMIPCEQpzC5XTG82BJwOyJrAfu00IXzgJCjyarQv6KrMk1l1nh4SARFjGA+40daMOeAHpWtF+HxkDEdSerdAncyEQFWoqY7XLFU1M9ZU+F7QeBBFz0T97fItS+alLZpvN35m+ZbeIHU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is; spf=pass smtp.mailfrom=pitsidianak.is; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b=0Nrp3QXG; arc=none smtp.client-ip=188.245.177.90 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b="0Nrp3QXG" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1777968855; bh=lunnIEDIwUnQNvPG0VVtgNP08wmfg3dV+L6Z49Gti7M=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=0Nrp3QXGSWlz8UVAVt+fQRNid/2cZ7GXlY7qjUxba3zcDFXxirjx8T4oegUSzH5MB XVOuuCBDjslapcuS0O4Rl/DHCfmlJNWonc6dmIhxOp/RYDll2u0TZsXc/yaQVBLA8V R16K+uvLD7BB6Of8I0vHzFnUKaVt/I32v4E5bZCRSedywhZ6Nrdj6fz5xDJrJ1S3dK UbHaDTwzDiJPkzGCJfAFsrlTrlOIeY8lkFpeb4huIPW89QWPLlSHRppJ6AwhjOEdc7 lgOC6OVb7LktT50pyz+bI46jD6aGQBAAN8fcOpMqzW1QTiAEypQPm2zYHNvqvStZlL 2KV/ruTtrGyCkKUaaiNpqFZ4+860JtLMQlSnRLKDeqwD4lhtbH7WpWwScHm573Fwgj d40xUEm/K7I9n0MYOedPbpNPbsEbDBzxQfKaRsK/lp+SUWShCmwhiNblkrnCIWGes6 SZA8o9FXgxOFuRmegz+B0lXCblAsuB2zTe8OPpINaB1ak8Fjliz0SbGpv9ROtSC7Dq keGShllL9GltqckswbEyduLsI6BfB4ZgqgAHzJ9/wj2zPX3P3VKA19pii+wyGnzWkO cfDWJJtWNtT64a8aXryY+QpF7A/3z1pmz0ye5kQFAjRhg9Z7kSBvnh4sqHblY/jCS8 ltFM56jnBqmHsP1bDW6YK1/o= From: Manos Pitsidianakis Date: Tue, 05 May 2026 11:14:01 +0300 Subject: [PATCH RFC 1/6] rust/bindings: generate virtio bindings Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260505-rust-virtio-v1-1-9563383909e4@pitsidianak.is> References: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> To: Miguel Ojeda Cc: Manos Pitsidianakis , Peter Hilber , Stefano Garzarella , Stefan Hajnoczi , Viresh Kumar , "Michael S. Tsirkin" , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , rust-for-linux@vger.kernel.org, Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Manos Pitsidianakis X-Developer-Signature: v=1; a=openpgp-sha256; l=828; i=manos@pitsidianak.is; h=from:subject:message-id; bh=lunnIEDIwUnQNvPG0VVtgNP08wmfg3dV+L6Z49Gti7M=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnArYWJTdTFsSklWWlJSb1lGK0tLTzRBelNJWUdYCmptd0pxd0tEVkNVcGlwckFH VGFKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWZtbTBnQUt DUkIzS2Nkd2YzNEowQUQ0RC85b09VZ201QlNYWk5GeVBZQmk1aVN0cnVQTWxHVFVwRHloN3JrTw pTQ25Wc1VvM0Y5cFJOdmx4ckNvcTA5QndqTnREeVF0REtKQXlHc2pMSlp4anhwYWlrNk9WWW9oR XBLNVFhS0IxClhJbUhCQ1ltOUdqODhqaks1SVlyVGR6VXNJU3ZseCtHQUFIbFNPeFBzOHlJWFE4 cGlsRWNzTE5yWnpzVnlsU3UKcVVCdnNmcHFoenJNSkZDUkVTYy9Gd3hqSkJZSndEaTRSQnB0MEs 3WHdFdmV5U2hNaWthZHF2bTJva0ZEbmZMbQptL2JVZWNZbDVhWmgrVGg0ZUppRmN2R3JydG9rSk dxWkpLcmFWc3djQ0lBSGxkNHRMbTZOWVhzL1FZelRJZzJhCkU4dGpUYmJWSFhjaE9Ib0xrYUIrR 3JhSzA5V0hubWI0NEZVN2dTMTljWnVwL3pqdnhDUytES0I1aFc3RzYyUmUKbFRFTWc3WG9OTVJl REtJVHVrejZRbVNVNDR5QmlMZW5GL25nNjM4SE1DOFdpcGx5dWYxWFNTZWY0RWtTRTlONQpDbyt XNDNTOW5URmZyeVpvckdtd2hCdEpUVmNzRmw0MlFOTFFYa2grbkdreDJtVFdwMFRubFNERXF3Yk JBRXdWCmpzWTd4UEpicGFXQWQrMHRpQ3A4RjI0S3F1eFdsY3Y1TnJvVUhMTFZDOHV2YTFvSzZpR 1lVaE1EZXRUb1hIN1gKME5HUUFFVmdqbko4M2xxTmJPazlzVEtlOGZRT2ZvbE9jU2JabG1kMTI3 RzRpMG5VOTJ6K0NaRkc2cE81cWdEVwpVMUx0b3N2UnYyMWdZaE5qdE5mNGQzWjRQdzR2S1JqaEE 2TjEzdWRXV1JCelEzek1hNE5zaUlKaHhndjdUT1FaCmlDQm10QT09Cj16ZWdXCi0tLS0tRU5EIF BHUCBNRVNTQUdFLS0tLS0K X-Developer-Key: i=manos@pitsidianak.is; a=openpgp; fpr=7C721DF9DB3CC7182311C0BF68BC211D47B421E1 Add virtio headers if CONFIG_VIRTIO is enabled. Signed-off-by: Manos Pitsidianakis --- rust/bindings/bindings_helper.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 083cc44aa952c2b29ab82d5d481063a1cf48bccf..2b0a3cf49fdaf14517afc88688c= 545aaa977b5c6 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -151,3 +151,8 @@ const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE =3D VM= _NOHUGEPAGE; #include "../../drivers/android/binder/rust_binder_events.h" #include "../../drivers/android/binder/page_range_helper.h" #endif + +#if defined(CONFIG_VIRTIO) +#include +#include +#endif /* defined(CONFIG_VIRTIO) */ --=20 2.47.3 From nobody Sun Jun 14 00:17:47 2026 Received: from mail.nessuent.net (mail.nessuent.net [188.245.177.90]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1B7373E9580; Tue, 5 May 2026 08:14:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=188.245.177.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968861; cv=none; b=hKZFF/dpTSKviZ+O9b7v7zUuJg2e3OHTOdzWb6DCI+gn0avIVwhlfyz+A40VDlG69ODPf2fbF1EBXMuD/6tYI2C/RNnZkwq0pSvKC2jwnxDwaGxH9TJw37h/K2MR8qWx622GAlOnFOQRr296eBIzvtkKuFQOHOL2CjR4G5LFyR0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968861; c=relaxed/simple; bh=UFc9kfWsblC+PG6Wl4DteBPxUyIgijd59/joXPqaXEM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=d+Ve2xTnI16h2iqWakFq6/F/lf0LiWhF7TvWKO/KYrQxrNWB+ee3dGNzI5NFDRPkyTCmWJ+U0JhZroWBL7gKykOznPHbSfKzdxBPbXLqZvISLD8vjdHXE/UFupWUv8yQRhxq2rZiUOtZvpiB8kF3+TwditG/tlJ91SniVqViVMA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is; spf=pass smtp.mailfrom=pitsidianak.is; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b=yworXja0; arc=none smtp.client-ip=188.245.177.90 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b="yworXja0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1777968857; bh=UFc9kfWsblC+PG6Wl4DteBPxUyIgijd59/joXPqaXEM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=yworXja0we+PIGum24JEeBgzktdR5jU1hU7viwLoyJNo2Ph1U4gE/AslV+ULYEJPB QX3qYZxIqyFr/nfTcK4RDmrKeRSeThFC60VmJWxFQgi2Lr8hBaN3vhTpRlFQeqT04H IG1F662Iych11Xubt6aFhOd82KRaIYn23cji5OTPaCG9JwGcU6Mxi5QBNV32DGqXHo sBpcrcbTYqhIJ1/LR4fEGjAu++XOyg2zxzJ5T+aMvpdJB+jyWvPjrRTRVFDEQJ69G9 iYDQxqCsYf1kCc78UxNWuQv6lHqIX9SWesYPv1cLAFtP4UKyjO+1GSKk5MQh5NngIn C8uKySJUafVma7EE+rA+IShF7qyaiUADJxjbXQiQdydOrEnLy26BOUTD7jvnulLg9S 7uKWb9UK3JqCeeFSnZaHwbxfsmg2H2y9WwR4V3QpYbBblzRWPqdAi27e2TDPr5pusq gU6NBWqVZkD/Jm4sqnJ8jiR1hS+5I5MB2yyn5mELOJADqJrg2sJQEcv8mfG/GGMd9p 3MEEbOPxsrPkMKEchmHcZH6zB6dfIrqXnfErT+pn+xKAmAlGltCdszTbMKe+nm7Pcz sNxzZAEmqeBKZpSdT1YrpH7vUo73xURLro4I6K7THCL2w4AGSPSPHnGxVgY1uDzqaF aYAZ2ZR2yLmv+aSz//fdHADs= From: Manos Pitsidianakis Date: Tue, 05 May 2026 11:14:02 +0300 Subject: [PATCH RFC 2/6] rust/helpers: add virtio.c Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260505-rust-virtio-v1-2-9563383909e4@pitsidianak.is> References: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> To: Miguel Ojeda Cc: Manos Pitsidianakis , Peter Hilber , Stefano Garzarella , Stefan Hajnoczi , Viresh Kumar , "Michael S. Tsirkin" , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , rust-for-linux@vger.kernel.org, Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Manos Pitsidianakis X-Developer-Signature: v=1; a=openpgp-sha256; l=2587; i=manos@pitsidianak.is; h=from:subject:message-id; bh=UFc9kfWsblC+PG6Wl4DteBPxUyIgijd59/joXPqaXEM=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnArYWJTVGg4bkFwd25Dd3ZNbnNvOUZRYmlDL2dpClNyQTVPYXo0MTNMTi9uMWh6 V09KQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWZtbTBnQUt DUkIzS2Nkd2YzNEowSkJwRC80anhkK3ZIWnEzbk1sVzNTOTVuNnIvU01CVnJJeHpaVS9YNHBsWg orRVdpMkZ6dkF4VFppWFZoTVJURTYwUUpIZTkySUVRYWtrRmVEQkxtUnNnelFyWWM4ZTZSMUtlb VNJbjBzcERwCjNrQ2xPN3BMNDQvYmdqdmJkSVd4TzVxMTQwVTJvYWdoZ1ExWmZnd0dSN2dTS2hJ L1krTmJxZ2lBbmVGd3hpcVkKRnIxWDAvK1RDOGRLWUhFL0FEMUxVWlNzSVFOaks5Zi9YbnJiWDN 1dkdxZWJaMXBFWFhycEs4ZEJsZGt5c1NqYworQ1VOUjAzd1Jhclo0cnJvNmFWRjVrclpWMXBGQz drRksvTGdwTlBMUVFDSUVmUDlMVE1wZDFNNHFOYXBUdG00ClNNc2tIS21hcWdjdkpPNzB6eVpIb GpSZHcvNm4yNkJSNlFmcmdra2JsNDN6THI5L21vck80aitZMmNUV0d2czYKUm84NjZ1b1J5dmVE eWRUenlrVWJvQ2lmR3pEdnJrMG5uam9YcFFyUFdEMDU4V1YwWEtvS2hHamNTOTltTy9zUQppSUl sUGV0dG91MzNUd1htZC9HUXFwSEVwUHloK1lrMHNZQWRNQ1JWa2YxS0Zsb0dCWXpGcmFMQjV2MT ZWdThPCmNiT2xJc0NRZHpXaXY2YTdIak9MU3JqSlhPS2NiUDFsdFpBQnQrTUpBalJkTFJUc0xUb 3cyazhGY1d4SEJMM1oKMkkvejRDZDlpZFhXNVpOb1ZUdUdjRFBDa0ZCUHNLSTczakJjK1Z4NlNY Z2g5YVp4b3FKYnhjclFqaHNpVWVQVQpTU0diOG1pNjV2ZlRlTG5aWHNqWWo1ZkhvYUVyLys0bWE 3K1poRFNPejBaNE5ZdXdQVHpNVjUzN3V1T0llNFBKCkJDNlpRUT09Cj03NXpHCi0tLS0tRU5EIF BHUCBNRVNTQUdFLS0tLS0K X-Developer-Key: i=manos@pitsidianak.is; a=openpgp; fpr=7C721DF9DB3CC7182311C0BF68BC211D47B421E1 Some internal kernel virtio API functions are inline macros, so define their symbols in a helper file. Signed-off-by: Manos Pitsidianakis Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- MAINTAINERS | 6 ++++++ rust/helpers/helpers.c | 3 +++ rust/helpers/virtio.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d1cc0e12fe1f004da89b1aa339116908f642e894..48c9c666d90b5a256ab6fae1f42= 508b789a0ce50 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27930,6 +27930,12 @@ F: include/uapi/linux/virtio_*.h F: net/vmw_vsock/virtio* F: tools/virtio/ =20 +VIRTIO CORE API BINDINGS [RUST] +M: Manos Pitsidianakis +L: virtualization@lists.linux.dev +S: Maintained +F: rust/helpers/virtio.c + VIRTIO CRYPTO DRIVER M: Gonglei L: virtualization@lists.linux.dev diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index a3c42e51f00a0990bea81ebce6e99bb397ce7533..84b54690d95be37699ef9a9c4d7= cedec0bbae6d3 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -62,6 +62,9 @@ #include "uaccess.c" #include "usb.c" #include "vmalloc.c" +#if defined(CONFIG_VIRTIO) +#include "virtio.c" +#endif /* defined(CONFIG_VIRTIO) */ #include "wait.c" #include "workqueue.c" #include "xarray.c" diff --git a/rust/helpers/virtio.c b/rust/helpers/virtio.c new file mode 100644 index 0000000000000000000000000000000000000000..cd8a811d59960e7b6aea1c08016= f4154b29d5a97 --- /dev/null +++ b/rust/helpers/virtio.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +__rust_helper bool +rust_helper_virtio_has_feature(const struct virtio_device *vdev, + unsigned int fbit) +{ + return virtio_has_feature(vdev, fbit); +} +__rust_helper void rust_helper_virtio_get_features(struct virtio_device *v= dev, + u64 *features_out) +{ + return virtio_get_features(vdev, features_out); +} + +__rust_helper int rust_helper_virtio_find_vqs(struct virtio_device *vdev, + unsigned int nvqs, + struct virtqueue *vqs[], + struct virtqueue_info vqs_info[], + struct irq_affinity *desc) +{ + return virtio_find_vqs(vdev, nvqs, vqs, vqs_info, desc); +} + +__rust_helper void rust_helper_virtio_device_ready(struct virtio_device *d= ev) +{ + return virtio_device_ready(dev); +} + +__rust_helper bool +rust_helper_virtio_is_little_endian(struct virtio_device *vdev) +{ + return virtio_is_little_endian(vdev); +} --=20 2.47.3 From nobody Sun Jun 14 00:17:47 2026 Received: from mail.nessuent.net (mail.nessuent.net [188.245.177.90]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 41FE63EAC65; Tue, 5 May 2026 08:14:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=188.245.177.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968863; cv=none; b=XQWQbd7Fd2eqjym47pT/uth7ozGm0o6BnTI67aYjsQap2AgjU5WIU6i62RfAbp2F2Ph4lJiWG84yc+w8H113NDjSjVWcBt/1Yh9z0k5GP819n2syEPyWObLxtHeiUqA8w7Xqwz8Pv8HCOwIKcsn55yZw8R/3YVXI44AB5vGVl90= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968863; c=relaxed/simple; bh=wj9k7L6CpyGtzkyu5jUNg1zs7S+8H0ealzEFGpas2Rk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=A6lxBNVHIwlFhdA8SVldgsYgZRfVybGMZu4MLWqWmwCxG+M73SkalCWxioF3P0O0HuYoYceR/zm7QLjcu6PgYt1dcSrnKH1G6uWzBPuHTUWGNLKrmbJKHPWzcxT779qj/YonivLjQghxZqr02Y03CCjvBOklkor5FN1k7Ec5TEA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is; spf=pass smtp.mailfrom=pitsidianak.is; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b=ekTjs1Z9; arc=none smtp.client-ip=188.245.177.90 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b="ekTjs1Z9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1777968858; bh=wj9k7L6CpyGtzkyu5jUNg1zs7S+8H0ealzEFGpas2Rk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=ekTjs1Z9e48i7oXEj9UuNJYGjfxRm6XH4V0Apr5yBb56O2eKxvBKe2evt82UoWgAw p4c/hMGJykLoHYR4lSFHP2SZSo8X3np8MdGgpVs5cacMjDBi3IfKeJAnzsD54l2PcY tPgnGLeq2rr9BpFNbOQtjuViz6v46NUjYLWnbufDINBGSxyq5utYJAOiMaGi9X/Jcr dUznT7015j+JJsw3TdxdmCuvy8Puwo57SIpUT4PK3BzmBNWFQa6WfmPteZKLbPLS8Z NHXlmpOFc/wTUnKYQ/klLveIC5AmXL4Ug3c2CbfXxau7ybjsYswk2pyQq2P9jaBv97 1Zh201oApLpsSLBOU0OE8Qw7WWmj8wEVpHEgwX2Ov5+VVAQuFhiWpHSz0NjjNt8uMK zCMN+aKcC7rCzL47V+C6uiXjphjgcJGZ9n7C71RMbA9bz6qmT/R7eBn7GcsAtgAjC4 s0JLrXY0SQxn/TqnMUTgP4OaetiDtAdGEAR8hpuVMWxX4FfD3pnLeZ6/JZACMr6P68 MEfmM/75zNnYvEzf8Nd7M3zq89UWN4LoxZTCN/5tISH615SpMl6F00SrpFmBeNee8e y91gB1qJDaNmt/+zOR+ArYw+iMHE5N2fndV1UQHBtc6PQgkz4ukCIqMetHbdCPMTbn +/Zjx8TYiXc3Ws9j8kNd6LwY= From: Manos Pitsidianakis Date: Tue, 05 May 2026 11:14:03 +0300 Subject: [PATCH RFC 3/6] rust: add virtio module Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260505-rust-virtio-v1-3-9563383909e4@pitsidianak.is> References: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> To: Miguel Ojeda Cc: Manos Pitsidianakis , Peter Hilber , Stefano Garzarella , Stefan Hajnoczi , Viresh Kumar , "Michael S. Tsirkin" , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , rust-for-linux@vger.kernel.org, Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Manos Pitsidianakis X-Developer-Signature: v=1; a=openpgp-sha256; l=26657; i=manos@pitsidianak.is; h=from:subject:message-id; bh=wj9k7L6CpyGtzkyu5jUNg1zs7S+8H0ealzEFGpas2Rk=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnArYWJUVXJYdDdDVDRxVUZJRjdkUnpYYVBsNGdoCk5LWkpjaiszcE5KdG1OTUsr MDJKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWZtbTB3QUt DUkIzS2Nkd2YzNEowSU9IRC85WncvZ2oraVFEeFhLaldzVXJBSnFmZDRyS0oyeFlnM3kzM1FkRg pjdUNlc2V4dHkvd2JxU2tFN2dRM244NWU0N3ZGNitkamE0cTZyWTNMV0pIb1hMMFVaak5lNFFSZ mxRTTVpZkcrClZWTHBTY0lRWnl4YmI4RHd4dUNyZkdEU3VjSm9TVHhucTJIT3JHR2VBVTN6U1BX cHkvd1pUNEJ1Z0RzU1hxc3YKQVJTRGNNV3pPUU9lWHB5UkUvOVRBaFhYb1pRaitta3lZdWJEdXF kWmtGcm1XdkdtS2o0RisxR3JKVGMxaVBGaAozUFMwVGRkTTZsQ0hCZDlJeEtIOFFXM1VPWXlrcU tvMWp2QTZBWnpOY01YZXJSNGlFbEtSd2xheml5bDRhUVRYCmI4UTFtT3ZjYzBJVmNpWmp2dXNCY 1pubHNzQno2K21PS055OXAxYytyTUlYTlZqYnJMd0V5K0J5YU5QMFpVTzMKMXY4NmVvblZyZVpt OWpQazROVWxQeHdHQnpWMlY3Mi8xeDVFeTJJT2M2d2VLK013R0c0SHh3ZzFpSk1GdTZMVApyNXl pL0M2L3JqcWFuZkcza0N4Qm11TFB3OTdReEZmRUdoaGtQUVB0OU80aU0wNExFTXpZSTRzYkRpUU 5WN3JjCnZsK3oyTkY1ekphSUxlM3FCdjVVSHQrRk56TUpVRTJGdHdSLzB6Umprd2E2ZW1JQUxsa DI4dTlQelpENmFCYVkKTGJIL21nYjBSM0x2dWk2UXFaRGx1RkdheUNJeW9YTElQNkxzQzk0MnVZ SVhzYjJuL0tGdW9BVkpzTEs0dnFnZQpyMWxkV3Nwc3hvcUpzZGJ3VFJBVW1FRGtMOW4xaXRNbDN JeFdOSTNPeDVEdkE4TzBRT2d2TENTM2dyTjJmUWtHCjRUYjZXdz09Cj1QYlJNCi0tLS0tRU5EIF BHUCBNRVNTQUdFLS0tLS0K X-Developer-Key: i=manos@pitsidianak.is; a=openpgp; fpr=7C721DF9DB3CC7182311C0BF68BC211D47B421E1 Add module that exposes bindings for the virtio API. Signed-off-by: Manos Pitsidianakis --- MAINTAINERS | 2 + rust/kernel/lib.rs | 2 + rust/kernel/scatterlist.rs | 2 +- rust/kernel/virtio.rs | 415 ++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/virtio/utils.rs | 65 +++++++ rust/kernel/virtio/virtqueue.rs | 181 ++++++++++++++++++ 6 files changed, 666 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 48c9c666d90b5a256ab6fae1f42508b789a0ce50..e8012f708df5d4ee858c82aec32= 69e615fc8caad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27935,6 +27935,8 @@ M: Manos Pitsidianakis L: virtualization@lists.linux.dev S: Maintained F: rust/helpers/virtio.c +F: rust/kernel/virtio.rs +F: rust/kernel/virtio/ =20 VIRTIO CRYPTO DRIVER M: Gonglei diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index d93292d47420f1f298a452ade5feefedce5ade86..c1fe1b06fd89e80f23c5de22aeb= 36c80f653e1ab 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -161,6 +161,8 @@ pub mod uaccess; #[cfg(CONFIG_USB =3D "y")] pub mod usb; +#[cfg(CONFIG_VIRTIO)] +pub mod virtio; pub mod workqueue; pub mod xarray; =20 diff --git a/rust/kernel/scatterlist.rs b/rust/kernel/scatterlist.rs index b83c468b5c63311f3a6d92f0f1bf05f6dfe12076..146e738cbd4351b41c11dd39a45= e20f404c5cd64 100644 --- a/rust/kernel/scatterlist.rs +++ b/rust/kernel/scatterlist.rs @@ -75,7 +75,7 @@ unsafe fn from_raw<'a>(ptr: *mut bindings::scatterlist) -= > &'a Self { =20 /// Obtain the raw `struct scatterlist *`. #[inline] - fn as_raw(&self) -> *mut bindings::scatterlist { + pub(crate) fn as_raw(&self) -> *mut bindings::scatterlist { self.0.get() } =20 diff --git a/rust/kernel/virtio.rs b/rust/kernel/virtio.rs new file mode 100644 index 0000000000000000000000000000000000000000..38e4f273ce76ab2dfa2e91b4ff8= c4d5ddde0121c --- /dev/null +++ b/rust/kernel/virtio.rs @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! VIRTIO abstraction. + +use crate::{ + bindings, + device_id::RawDeviceId, + error::{ + from_result, + to_result, + Error, + Result, // + }, + ffi::c_uint, + prelude::*, + types::Opaque, // +}; + +use core::{ + marker::PhantomData, + pin::Pin, // +}; + +pub mod utils; +pub mod virtqueue; + +/// IdTable type for virtio drivers. +pub type IdTable =3D &'static dyn crate::device_id::IdTable; + +/// A VIRTIO device id. +/// +/// [`struct virtio_device_id`]: srctree/include/linux/mod_devicetable.h +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct DeviceId(bindings::virtio_device_id); + +// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct virti= o_device_id` and +// does not add additional invariants, so it's safe to transmute to `RawTy= pe`. +unsafe impl RawDeviceId for DeviceId { + type RawType =3D bindings::virtio_device_id; +} + +impl DeviceId { + #[inline] + /// Create a new device id + pub const fn new(device: VirtioID) -> Self { + Self::new_with_vendor(device, VIRTIO_DEV_ANY_ID) + } + + /// Create a new device id with vendor + pub const fn new_with_vendor(device: VirtioID, vendor: u32) -> Self { + // Replace with `bindings::of_device_id::default()` once stabilize= d for `const`. + // SAFETY: FFI type is valid to be zero-initialized. + let mut ret: bindings::virtio_device_id =3D unsafe { core::mem::ze= roed() }; + ret.device =3D device as u32; + ret.vendor =3D vendor; + Self(ret) + } +} + +/// Create a virtio `IdTable` with its alias for modpost. +#[macro_export] +macro_rules! virtio_device_table { + ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $tabl= e_data:expr) =3D> { + const $table_name: $crate::device_id::IdArray< + $crate::virtio::DeviceId, + $id_info_type, + { $table_data.len() }, + > =3D $crate::device_id::IdArray::new_without_index($table_data); + + $crate::module_device_table!("virtio", $module_table_name, $table_= name); + }; +} + +/// Declares a kernel module that exposes a single virtio driver. +#[macro_export] +macro_rules! module_virtio_driver { +($($f:tt)*) =3D> { + $crate::module_driver!(, $crate::virtio::Adapter, { $($f)* }); +}; +} + +/// The Virtio driver trait. +/// +/// Drivers must implement this trait in order to get a virtio driver regi= stered. +pub trait Driver: Send { + /// The type holding information about each device id supported by the= driver. + // TODO: Use `associated_type_defaults` once stabilized: + // + // ``` + // type IdInfo: 'static =3D (); + // ``` + type IdInfo: 'static; + + /// The table of device ids supported by the driver. + const ID_TABLE: IdTable; + + /// virtio driver probe. + /// + /// Called when a new virtio device is added or discovered. Implemente= rs should + /// attempt to initialize the device here, but not sleep, since driver= data is set after this + /// method returns successfully. + fn probe(dev: &Device) -> impl PinInit; + + /// virtio driver init. + /// + /// Called after a virtio device is probed successfully, can sleep. + fn init(&self, dev: &Device) -> Result; + + /// virtio driver remove. + /// + /// Called when a [`Device`] is removed from its [`Driver`]. Implement= ing this callback + /// is optional. + /// + /// This callback serves as a place for drivers to perform teardown op= erations that require a + /// `&Device` or `&Device` reference. For instance, drive= rs may try to perform I/O + /// operations to gracefully tear down the device. + /// + /// Otherwise, release operations for driver resources should be perfo= rmed in `Self::drop`. + fn remove(dev: &Device, this: Pin<&Self>); +} + +/// Abstraction for the virtio device structure (`struct virtio_device`). +/// +/// [`struct virtio_device`]: srctree/include/linux/virtio.h +#[repr(transparent)] +pub struct Device( + Opaque, + PhantomData, +); + +impl Device { + #[inline] + fn as_raw(&self) -> *mut bindings::virtio_device { + self.0.get() + } +} + +// SAFETY: `virtio::Device` is a transparent wrapper of `struct virtio_dev= ice`. +// The offset is guaranteed to point to a valid device field inside `virti= o::Device`. +unsafe impl crate::device::AsBusDevice<= Ctx> for Device { + const OFFSET: usize =3D core::mem::offset_of!(bindings::virtio_device,= dev); +} + +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend= on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); + +impl Device { + // TODO: return VirtioID + /// Returns the virtio device ID. + #[inline] + pub fn device_id(&self) -> u32 { + // SAFETY: By its type invariant `self.as_raw` is always a valid p= ointer to a + // `struct virtio_device`. + unsafe { (*self.as_raw()).id.device } + } + + /// Returns the virtio vendor ID. + #[inline] + pub fn vendor_id(&self) -> u32 { + // SAFETY: `self.as_raw` is a valid pointer to a `struct virtio_de= vice`. + unsafe { (*self.as_raw()).id.vendor } + } + + /// Reset device. + #[doc(alias =3D "virtio_reset_device")] + pub fn reset(&self) { + // SAFETY: By its type invariant `self.as_raw` is always a valid p= ointer to a + // `struct virtio_device`. + unsafe { bindings::virtio_reset_device(self.as_raw()) } + } + + /// Mark device as ready. + #[doc(alias =3D "virtio_device_ready")] + pub fn ready(&self) { + // SAFETY: By its type invariant `self.as_raw` is always a valid p= ointer to a + // `struct virtio_device`. + unsafe { bindings::virtio_device_ready(self.as_raw()) } + } + + /// Return virtqueues for this device. + #[doc(alias =3D "virtio_find_vqs")] + pub fn find_vqs( + &self, + info: &[virtqueue::VirtqueueInfo], + ) -> Result> { + let mut vqs =3D KVec::with_capacity(info.len(), GFP_KERNEL)?; + // SAFETY: By its type invariant `self.as_raw` is always a valid p= ointer to a + // `struct virtio_device`. + to_result(unsafe { + bindings::virtio_find_vqs( + self.as_raw(), + info.len().try_into()?, + vqs.spare_capacity_mut().as_mut_ptr().cast(), + info.as_ptr().cast_mut().cast(), + core::ptr::null_mut(), + ) + })?; + // SAFETY: virtio_find_vqs returned successfully so `vqs` must be = populated. + unsafe { vqs.inc_len(info.len()) }; + Ok(vqs) + } + + /// Delete virtqueues from this device. + pub fn del_vqs(&self) { + // SAFETY: By its type invariant `self.as_raw` is always a valid p= ointer to a + // `struct virtio_device`. + let config =3D unsafe { (*self.as_raw()).config }; + // SAFETY: `config` points to a valid virtqueue config struct. + if let Some(del_vqs) =3D unsafe { (*config).del_vqs } { + // SAFETY: By its type invariant `self.as_raw` is always a val= id pointer to a + // `struct virtio_device`. + unsafe { del_vqs(self.as_raw()) } + } + } + + /// Checks if the device has a feature bit. + pub fn has_feature(&self, fbit: c_uint) -> bool { + // SAFETY: By its type invariant `self.as_raw` is always a valid p= ointer to a + // `struct virtio_device`. + unsafe { bindings::virtio_has_feature(self.as_raw(), fbit) } + } + + /// Return all feature bits for this device. + pub fn get_features(&self) -> u64 { + let mut features =3D 0; + // SAFETY: By its type invariant `self.as_raw` is always a valid p= ointer to a + // `struct virtio_device`. + unsafe { bindings::virtio_get_features(self.as_raw(), &raw mut fea= tures) }; + features + } +} + +impl AsRef> = for Device { + fn as_ref(&self) -> &crate::device::Device { + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a p= ointer to a valid + // `struct virtio_device`. + let dev =3D unsafe { core::ptr::addr_of_mut!((*self.as_raw()).dev)= }; + + // SAFETY: `dev` points to a valid `struct device`. + unsafe { crate::device::Device::from_raw(dev) } + } +} + +// SAFETY: A `Device` can be used rom any thread. +unsafe impl Send for Device {} + +// SAFETY: `Device` can be shared among threads because all methods of `De= vice` +// (i.e. `Device) are thread safe. +unsafe impl Sync for Device {} + +/// An adapter for the registration of virtio drivers. +pub struct Adapter(T); + +// SAFETY: +// - `bindings::virtio_driver` is a C type declared as `repr(C)`. +// - `T` is the type of the driver's device private data. +// - `struct virtio_driver` embeds a `struct device_driver`. +// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. +unsafe impl crate::driver::DriverLayout for Adapter { + type DriverType =3D bindings::virtio_driver; + type DriverData =3D T; + const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); +} + +// SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if +// a preceding call to `register` has been successful. +unsafe impl crate::driver::RegistrationOps for Adapte= r { + unsafe fn register( + vdrv: &Opaque, + name: &'static CStr, + module: &'static ThisModule, + ) -> Result { + // SAFETY: It's safe to set the fields of `struct virtio_driver` o= n initialization. + unsafe { + (*vdrv.get()).driver.name =3D name.as_char_ptr(); + (*vdrv.get()).id_table =3D T::ID_TABLE.as_ptr(); + (*vdrv.get()).probe =3D Some(Self::probe_callback); + (*vdrv.get()).remove =3D Some(Self::remove_callback); + } + + // SAFETY: `vdrv` is guaranteed to be a valid `DriverType`. + to_result(unsafe { bindings::__register_virtio_driver(vdrv.get(), = module.0) }) + } + + unsafe fn unregister(vdrv: &Opaque) { + // SAFETY: `vdrv` is guaranteed to be a valid `DriverType`. + unsafe { bindings::unregister_virtio_driver(vdrv.get()) } + } +} + +impl Adapter { + extern "C" fn probe_callback(vdev: *mut bindings::virtio_device) -> c_= int { + // SAFETY: The kernel only ever calls the probe callback with a va= lid pointer to a `struct + // virtio_device`. + // + // INVARIANT: `vdev` is valid for the duration of `probe_callback(= )`. + let dev =3D unsafe { &*vdev.cast::>() }; + from_result(|| { + let data =3D T::probe(dev); + + dev.as_ref().set_drvdata(data)?; + // SAFETY: `Device::set_drvdata()` was just called so it's saf= e to borrow the data. + let data =3D unsafe { dev.as_ref().drvdata_borrow::() }; + T::init(&data, dev)?; + Ok(0) + }) + } + + extern "C" fn remove_callback(vdev: *mut bindings::virtio_device) { + // SAFETY: The kernel only ever calls the remove callback with a v= alid pointer to a `struct + // virtio_device`. + // + // INVARIANT: `vdev` is valid for the duration of `remove_callback= ()`. + let dev =3D unsafe { &*vdev.cast::>() }; + + // SAFETY: `remove_callback` is only ever called after a successfu= l call to + // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called + // and stored a `Pin>`. + let data =3D unsafe { dev.as_ref().drvdata_borrow::() }; + + T::remove(dev, data); + } +} + +/// Any vendor +pub const VIRTIO_DEV_ANY_ID: u32 =3D 0xffffffff; + +/// Virtio IDs +/// +/// C header: [`include/uapi/linux/virtio_ids.h`](srctree/include/uapi/lin= ux/virtio_ids.h) +#[repr(u32)] +pub enum VirtioID { + /// virtio net + Net =3D bindings::VIRTIO_ID_NET, + /// virtio block + Block =3D bindings::VIRTIO_ID_BLOCK, + /// virtio console + Console =3D bindings::VIRTIO_ID_CONSOLE, + /// virtio rng + Rng =3D bindings::VIRTIO_ID_RNG, + /// virtio balloon + Balloon =3D bindings::VIRTIO_ID_BALLOON, + /// virtio ioMemory + IOMem =3D bindings::VIRTIO_ID_IOMEM, + /// virtio remote processor messaging + RPMSG =3D bindings::VIRTIO_ID_RPMSG, + /// virtio scsi + Scsi =3D bindings::VIRTIO_ID_SCSI, + /// 9p virtio console + NineP =3D bindings::VIRTIO_ID_9P, + /// virtio WLAN MAC + Mac80211Wlan =3D bindings::VIRTIO_ID_MAC80211_WLAN, + /// virtio remoteproc serial link + RPROCSerial =3D bindings::VIRTIO_ID_RPROC_SERIAL, + /// Virtio caif + CAIF =3D bindings::VIRTIO_ID_CAIF, + /// virtio memory balloon + MemoryBalloon =3D bindings::VIRTIO_ID_MEMORY_BALLOON, + /// virtio GPU + GPU =3D bindings::VIRTIO_ID_GPU, + /// virtio clock/timer + Clock =3D bindings::VIRTIO_ID_CLOCK, + /// virtio input + Input =3D bindings::VIRTIO_ID_INPUT, + /// virtio vsock transport + VSock =3D bindings::VIRTIO_ID_VSOCK, + /// virtio crypto + Crypto =3D bindings::VIRTIO_ID_CRYPTO, + /// virtio signal distribution device + SignalDist =3D bindings::VIRTIO_ID_SIGNAL_DIST, + /// virtio pstore device + Pstore =3D bindings::VIRTIO_ID_PSTORE, + /// virtio IOMMU + Iommu =3D bindings::VIRTIO_ID_IOMMU, + /// virtio mem + Mem =3D bindings::VIRTIO_ID_MEM, + /// virtio sound + Sound =3D bindings::VIRTIO_ID_SOUND, + /// virtio filesystem + FS =3D bindings::VIRTIO_ID_FS, + /// virtio pmem + PMem =3D bindings::VIRTIO_ID_PMEM, + /// virtio rpmb + RPMB =3D bindings::VIRTIO_ID_RPMB, + /// virtio mac80211-hwsim + Mac80211Hwsim =3D bindings::VIRTIO_ID_MAC80211_HWSIM, + /// virtio video encoder + VideoEncoder =3D bindings::VIRTIO_ID_VIDEO_ENCODER, + /// virtio video decoder + VideoDecoder =3D bindings::VIRTIO_ID_VIDEO_DECODER, + /// virtio SCMI + SCMI =3D bindings::VIRTIO_ID_SCMI, + /// virtio nitro secure module + NitroSecMod =3D bindings::VIRTIO_ID_NITRO_SEC_MOD, + /// virtio i2c adapter + I2CAdapter =3D bindings::VIRTIO_ID_I2C_ADAPTER, + /// virtio watchdog + Watchdog =3D bindings::VIRTIO_ID_WATCHDOG, + /// virtio can + CAN =3D bindings::VIRTIO_ID_CAN, + /// virtio dmabuf + DMABuf =3D bindings::VIRTIO_ID_DMABUF, + /// virtio parameter server + ParamServ =3D bindings::VIRTIO_ID_PARAM_SERV, + /// virtio audio policy + AudioPolicy =3D bindings::VIRTIO_ID_AUDIO_POLICY, + /// virtio bluetooth + BT =3D bindings::VIRTIO_ID_BT, + /// virtio gpio + GPIO =3D bindings::VIRTIO_ID_GPIO, + /// virtio spi + SPI =3D bindings::VIRTIO_ID_SPI, +} diff --git a/rust/kernel/virtio/utils.rs b/rust/kernel/virtio/utils.rs new file mode 100644 index 0000000000000000000000000000000000000000..0c078202915127d38c3ba0bb167= 5c7f4cd94df6e --- /dev/null +++ b/rust/kernel/virtio/utils.rs @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Helper types and utilities + +macro_rules! endian_type { + (le $old_type:ident, $new_type:ident) =3D> { + endian_type!($old_type, $new_type, to_le, from_le); + }; + (be $old_type:ident, $new_type:ident) =3D> { + endian_type!($old_type, $new_type, to_be, from_be); + }; + ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) =3D= > { + /// An unsigned integer type of with an explicit endianness. + #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, pin_init::Zer= oable)] + #[repr(transparent)] + pub struct $new_type($old_type); + + $crate::static_assert!( + ::core::mem::align_of::<$new_type>() =3D=3D ::core::mem::align= _of::<$old_type>() + ); + $crate::static_assert!( + ::core::mem::size_of::<$new_type>() =3D=3D ::core::mem::size_o= f::<$old_type>() + ); + + impl $new_type { + /// Convert to CPU/native endianness. + pub const fn to_cpu(self) -> $old_type { + $old_type::$from_new(self.0) + } + } + + impl PartialEq<$old_type> for $new_type { + fn eq(&self, other: &$old_type) -> bool { + self.0 =3D=3D $old_type::$to_new(*other) + } + } + + impl PartialEq<$new_type> for $old_type { + fn eq(&self, other: &$new_type) -> bool { + $old_type::$to_new(other.0) =3D=3D *self + } + } + + impl From<$new_type> for $old_type { + fn from(v: $new_type) -> $old_type { + v.to_cpu() + } + } + + impl From<$old_type> for $new_type { + fn from(v: $old_type) -> $new_type { + $new_type($old_type::$to_new(v)) + } + } + }; +} + +endian_type!(u16, Le16, to_le, from_le); +endian_type!(u32, Le32, to_le, from_le); +endian_type!(u64, Le64, to_le, from_le); +endian_type!(usize, LeSize, to_le, from_le); +endian_type!(u16, Be16, to_be, from_be); +endian_type!(u32, Be32, to_be, from_be); +endian_type!(u64, Be64, to_be, from_be); +endian_type!(usize, BeSize, to_be, from_be); diff --git a/rust/kernel/virtio/virtqueue.rs b/rust/kernel/virtio/virtqueue= .rs new file mode 100644 index 0000000000000000000000000000000000000000..754fdad8c10199ee10e77658a7e= 773c8e4e95286 --- /dev/null +++ b/rust/kernel/virtio/virtqueue.rs @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Virtqueue functionality. + +use crate::{ + alloc::{ + Flags, // + }, + bindings, + error::{ + code::EINVAL, + to_result, + Result, // + }, + scatterlist::SGEntry, + str::CStr, + types::Opaque, + virtio::Device, // +}; + +use core::{ + ffi::c_uint, + ptr::NonNull, // +}; + +/// Info for a virtqueue. +/// +/// [`struct virtqueue_info`]: srctree/include/linux/virtio_config.h +#[doc(alias =3D "virtqueue_info")] +#[repr(transparent)] +pub struct VirtqueueInfo(Opaque); + +impl VirtqueueInfo { + /// Create a new [`VirtqueueInfo`] + pub const fn new( + name: &'static CStr, + ctx: bool, + callback: unsafe extern "C" fn(*mut bindings::virtqueue), + ) -> Self { + Self(Opaque::new(bindings::virtqueue_info { + name: name.as_ptr(), + ctx, + callback: Some(callback), + })) + } +} + +/// An opaque handler for a virtqueue. +/// +/// [`struct virtqueue`]: srctree/include/linux/virtio.h +#[repr(transparent)] +pub struct Virtqueue(Opaque); + +impl Virtqueue { + /// Create a [`Virtqueue`] from a raw pointer. + /// + /// # Safety + /// + /// Callers must ensure that `ptr` is a properly initialized valid `vi= rtqueue` pointer. + #[inline] + pub unsafe fn from_raw<'a>(ptr: *mut bindings::virtqueue) -> &'a Self { + // SAFETY: The safety requirements of this function guarantee that= `ptr` is a valid + // pointer to a `struct virtqueue` for the duration of `'a`. + unsafe { &*ptr.cast() } + } + + /// Obtain the raw `struct virtqueue *`. + #[inline] + pub(crate) fn as_raw(&self) -> *mut bindings::virtqueue { + self.0.get() + } + + /// Get the [`Device`] associated with this virtqueue. + pub fn dev(&self) -> &Device { + // SAFETY: the pointer has been promised to be valid when self was= created + let vdev =3D unsafe { *self.as_raw() }.vdev; + // SAFETY: the pointer has been promised to be valid when self was= created + unsafe { &*vdev.cast::>() } + } + + /// Get the vring size. + #[doc(alias =3D "virtqueue_get_vring_size")] + pub fn vring_size(&self) -> u32 { + // SAFETY: the pointer has been promised to be valid when self was= created + unsafe { bindings::virtqueue_get_vring_size(self.as_raw()) } + } + + /// Notify virtqueue. + #[doc(alias =3D "virtqueue_notify")] + pub fn notify(&self) -> bool { + // SAFETY: the pointer has been promised to be valid when self was= created + unsafe { bindings::virtqueue_notify(self.as_raw()) } + } + + /// Kick and prepare virtqueue. + #[doc(alias =3D "virtqueue_kick_prepare")] + pub fn kick_prepare(&self) -> bool { + // SAFETY: the pointer has been promised to be valid when self was= created + unsafe { bindings::virtqueue_kick_prepare(self.as_raw()) } + } + + /// Kick virtqueue. + #[doc(alias =3D "virtqueue_kick")] + pub fn kick(&self) -> bool { + // SAFETY: the pointer has been promised to be valid when self was= created + unsafe { bindings::virtqueue_kick(self.as_raw()) } + } + + /// Enable virtqueue's callback. + #[doc(alias =3D "virtqueue_enable_cb")] + pub fn enable_cb(&self) -> bool { + // SAFETY: the pointer has been promised to be valid when self was= created + unsafe { bindings::virtqueue_enable_cb(self.as_raw()) } + } + + /// Disable virtqueue's callback. + #[doc(alias =3D "virtqueue_disable_cb")] + pub fn disable_cb(&self) { + // SAFETY: the pointer has been promised to be valid when self was= created + unsafe { bindings::virtqueue_disable_cb(self.as_raw()) } + } + + /// Get a buffer from the virtqueue, if available. + #[doc(alias =3D "virtqueue_get_buf")] + pub fn get_buf(&'_ self) -> Option<(NonNull, u32)> { + let mut len =3D 0; + // SAFETY: the pointer has been promised to be valid when self was= created + let ptr =3D unsafe { bindings::virtqueue_get_buf(self.as_raw(), &m= ut len) }; + Some((NonNull::new(ptr.cast())?, len)) + } + + /// Make a device write-only buffer available. + #[doc(alias =3D "virtqueue_add_inbuf")] + pub fn add_inbuf(&'_ self, sg: &SGEntry, token: *mut u8, gfp: Flags) -= > Result { + // SAFETY: the pointer has been promised to be valid when self was= created + to_result(unsafe { + bindings::virtqueue_add_inbuf(self.as_raw(), sg.as_raw(), 1, t= oken.cast(), gfp.as_raw()) + }) + } + + /// Make a device read-only buffer available. + #[doc(alias =3D "virtqueue_add_outbuf")] + pub fn add_outbuf(&'_ self, sg: &SGEntry, token: *mut u8, gfp: Flags) = -> Result { + // SAFETY: the pointer has been promised to be valid when self was= created + to_result(unsafe { + bindings::virtqueue_add_outbuf( + self.as_raw(), + sg.as_raw(), + 1, + token.cast(), + gfp.as_raw(), + ) + }) + } + + /// Add a list of scatter-gather lists to virtqueue. + #[doc(alias =3D "virtqueue_add_sgs")] + pub fn add_sgs( + &'_ self, + sgs: &[&SGEntry], + out_sgs: c_uint, + in_sgs: c_uint, + token: *mut u8, + gfp: Flags, + ) -> Result { + if (out_sgs + in_sgs) as usize !=3D sgs.len() { + return Err(EINVAL); + } + // SAFETY: the pointer has been promised to be valid when self was= created + to_result(unsafe { + bindings::virtqueue_add_sgs( + self.as_raw(), + sgs.as_ptr().cast_mut().cast(), + out_sgs, + in_sgs, + token.cast(), + gfp.as_raw(), + ) + }) + } +} --=20 2.47.3 From nobody Sun Jun 14 00:17:47 2026 Received: from mail.nessuent.net (mail.nessuent.net [188.245.177.90]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4AA4C3EB7FB; Tue, 5 May 2026 08:14:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=188.245.177.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968862; cv=none; b=DtEb19Y8GHRwUrhXTyD+ktVBg5s6px/+ZBgy/y7dkBju6NbXUUoVWrwwEkA1YAQBnHbXeEMrUMufwYedBgVQd56Ofc2i/zVI0MZpTyTyvasE0ZcgGhAEcmsBjw6XNS6aFf9xdxYmR+dI/GbfJdlHgPi2WkxoJjXf70TJsVh8YLg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968862; c=relaxed/simple; bh=ueMYbnhP380gUpqP1QHJlQrrjstYCaH5Rry1n19OITA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=FfhK4U9W6Tuq3wyTbpezu0PIioImiOwicQUBWvtmHw42iJ5dsm2YofyLBmUI8H015O3j46Qg5+6iUsTJNxuLbxSwNs3Dg7L8F2F+VmsBfcVcmyMAkMImDx8aB3fk9qw9rlbD59hZ98IlxX61iGf859tawgzNsw7dWnhzAgY7dZI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is; spf=pass smtp.mailfrom=pitsidianak.is; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b=C6dS7Ggu; arc=none smtp.client-ip=188.245.177.90 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b="C6dS7Ggu" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1777968859; bh=ueMYbnhP380gUpqP1QHJlQrrjstYCaH5Rry1n19OITA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=C6dS7Ggudn106qSECnCYEnw6zPdpuMkaMKISzw96hxICj3Smn/i23RwM2xeVpD7VR VcrMEfy0VReJN75gSU8KDQ6A68wJxTGxkESAHTeatlc3zv19DLPkO+NJ93/KHCEB/L qKNVa7KqHC8hd029QLBXfhmQqfAIS6M0kccBdXAhq3dGGvPC6bxItP0Iyti56GlfKH fv5tnrKqhWth4uG/lhp8BoTBj4/8HW+7X4H1ZYy71VFH2672agSEwRSvIwZitgl4fo 3m0J+tVRmnU00sqkHt/5hy6j8U3pU4vYquDNf3wU/P4C1ilPwhOtCVs19CNH3wNTCD HxamI4emAZFDfZMAOoiDC5LXPh8BW0FaFfvXnonTEcEBLG72H786lf6vqIF6SPGpY7 BGgGIim2Xc+t/ES6MEMDAMH0ZJpkoCScqspyyu8uzrGMaReOCZsqOGxtRi0PJyBR50 2t9NJKMxze8ETwLAl2aWjCZFL/OyTUe369MAPkE6MqUeQWInMH10AQesB0ewQHO+5C MkIYwa/E7CPnNKIJ4ZF/7O5KC4RDfhkv/HSXeEeozXWBVm3DCP1+FhqGOIR8r6ISb0 DgXzpEczaNS+eyZloA7vLiBMCMybR3wp3CcZOm6GuQDEoGjwEfBS6yy9FTPvv/LFhu 31rUTyh//+4zgzEvJVjop7ng= From: Manos Pitsidianakis Date: Tue, 05 May 2026 11:14:04 +0300 Subject: [PATCH RFC 4/6] rust/scatterlist: add SGEntry::init_one Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260505-rust-virtio-v1-4-9563383909e4@pitsidianak.is> References: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> To: Miguel Ojeda Cc: Manos Pitsidianakis , Peter Hilber , Stefano Garzarella , Stefan Hajnoczi , Viresh Kumar , "Michael S. Tsirkin" , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , rust-for-linux@vger.kernel.org, Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Manos Pitsidianakis X-Developer-Signature: v=1; a=openpgp-sha256; l=1545; i=manos@pitsidianak.is; h=from:subject:message-id; bh=ueMYbnhP380gUpqP1QHJlQrrjstYCaH5Rry1n19OITA=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnArYWJUQUhMbGhZMXBuajBuNFlFTWZOT0x2NGQ5CnFLMEpPc2xqSFIwbWJ2Qlov M2VKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWZtbTB3QUt DUkIzS2Nkd2YzNEowRWk3RC80OGZLakEvTHV3Vkd3ZkdYeXlHQW9uZzdkS042UjhWbVNtMEhiUQ pOWHpZTERjelM3elBCTVhMNkJLOFVXS2lqMVNKNTVOK2N3SDF5eFdpWDFzZ0t3V1N4NHZ1UzRmS 2VlT2FvRmhhCkV6SHE5bCtsRC9kYzZkUU56UnJ5RFJNci9Wa1VUVjUyUk8zd3RPMUh2U0UraXl0 OHRBTGdZazVPRVc2R1NiZjAKaGp5ZDhmWDFvaWtMOFBHMnJlWkdWMGtSMENtNURhY0lHbklVam9 tL0Jrc0c2QUY4NnF4QnBrSzVHdHVMQ3lKRQpjNGNic0lEaVA5L1JSR0pvMDNKUWo2MkEwT0k1bU swaC9MejdqV1FwaTgyY0RUM0RMMGJ4Q1AraW82WkpwLzFnCmU4RVpuNFQ3Rkhtakd5VTlVdnhUU i9yTUlES1NFQXlud3pMcm9YZHFKK0owNXRKTTkyQ2RHVjZxQ2hUQ0dtSHgKWTFMdUlweGtQdUJO YUZXbEUrL0RaN290RmRMVVNBNll2MXBnbDh0WmlGTHp5Uk4xZHFzTjMxbUhpcm1EL1NWawpTZ1F 4ZmwwWThSOHNYWXN0T1NnVGtOUjlvVzhpanF0dVB5MVdMOWlZalpNNVB2NG9FNHJEQVhWMys0Yk JMQVVHCmVDWDh5U3hQeE5JeEZ2ajlJZ1E3dm4wQloxWmxWL3R6N1lVaDZsbDNKMWpZdG1jaFI2Z 1VyTEZvTGZUVGZHMWkKZ3h4MGJGYXhlaldDaFRhVFUrRldVZ25KL1VpQmxEYkllbWNEdys1RTFE aEFNODRmQlo4SmFDQXhmUEZIR2UyUgorV0hHU0NkSllyYlJueEgyZU00bmxsOXhmUXIxRGd0TG9 QZWY3L0VmcUpkT2VXcmdxOGNWQWI1aDRKeWJXWGszCmxraEdsdz09Cj1PaDFvCi0tLS0tRU5EIF BHUCBNRVNTQUdFLS0tLS0K X-Developer-Key: i=manos@pitsidianak.is; a=openpgp; fpr=7C721DF9DB3CC7182311C0BF68BC211D47B421E1 Add a method to allow creation of an SGEntry with borrowed data. Analogous of `sg_init_one` in C. Signed-off-by: Manos Pitsidianakis Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- rust/kernel/scatterlist.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/rust/kernel/scatterlist.rs b/rust/kernel/scatterlist.rs index 146e738cbd4351b41c11dd39a45e20f404c5cd64..b065762af1a734fcdd5d3acde89= 199f1a626fd89 100644 --- a/rust/kernel/scatterlist.rs +++ b/rust/kernel/scatterlist.rs @@ -95,6 +95,24 @@ pub fn dma_len(&self) -> ResourceSize { // SAFETY: `self.as_raw()` is a valid pointer to a `struct scatter= list`. unsafe { bindings::sg_dma_len(self.as_raw()) }.into() } + + /// Initialize a new entry with borrowed data. + /// + /// # Safety + /// + /// Callers must ensure that: + /// - `buf` is a valid pointer + /// - `buf_len` describes a valid allocation size for this pointer + pub unsafe fn init_one( + val: &'_ mut core::mem::MaybeUninit, + buf: NonNull, + buf_len: u32, + ) -> &'_ Self { + // SAFETY: `val` points to a correctly sized `struct scatterlist`. + unsafe { bindings::sg_init_one(val.as_mut_ptr(), buf.as_ptr().cast= (), buf_len) }; + // SAFETY: `val` points to an initialized `struct scatterlist`. + unsafe { Self::from_raw(val.as_mut_ptr()) } + } } =20 /// The borrowed generic type of an [`SGTable`], representing a borrowed o= r externally managed --=20 2.47.3 From nobody Sun Jun 14 00:17:47 2026 Received: from mail.nessuent.net (mail.nessuent.net [188.245.177.90]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 95CF73EC2EB; Tue, 5 May 2026 08:14:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=188.245.177.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968864; cv=none; b=qFqKd4qEv4V2ujfVjGPsNELEbOl48CAUnFSHNIr7+NIJFjcckp+7A9C+AsRh/MpAk3ZLMjJwMS78+eN9VLOoPNqtAMEbdyxS7+X/lcVAkMCwCLzPTkD86kC//ki0GvWgh+k/B+Rck1+TXSPAHB3xl7jA/LAywGipZq/VyY5nVmY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968864; c=relaxed/simple; bh=kgKzIAsgVjpYWlipSjiAGnVMQwoh2Eyh3sSKdi6XpN8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bVu4Tx+YMtioRgAQVP7/lo4SUNCJFKpo4rI3LvdBYFwNpN49gfGd6NMdu+xlPDOG3vbjAEj5zU7Fs3SnjXYT2uxx3bkL9Hnls3PjO7RIspmupc2kRO9595FSHue3rYo5LGabDoEgW3bhvpBAO0TrQaWCorSnriT7kFhcr3kHJVU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is; spf=pass smtp.mailfrom=pitsidianak.is; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b=fmFKW74O; arc=none smtp.client-ip=188.245.177.90 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b="fmFKW74O" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1777968861; bh=kgKzIAsgVjpYWlipSjiAGnVMQwoh2Eyh3sSKdi6XpN8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=fmFKW74OaftEZbgGt3jLLjJEBdLTCZaqOlxp35uwnHxDQO4cHCmOvySCSfBw4WHx2 2NrxrCtHF6v26R7wwH9aRVqjP4V7oNLGmOav3oAcqIhpy+l5TZ8d0fW5VHJe1/LTuG +W91OXczkWzLDWOwrgEu2euhdy9MvrKjVFKo2spFWxH4FHE0r0Hdhvpx/V1DXz/8Gg 1Bd5A+h9WIxiBV9EA4fbeHpITlbqhKUbx493AE9IgY6kAye2J7sWK7LO/XHWkF19VB 2Kmr0WdBCFlEGLZ0FF00aUXDarx2sWoJZcFLsf4NaD4ktUnmsF5RPvcEBs89mQiXcs 8wQ9zPOfuz0GZ8oYdEnv5jYk0PbIuC6ySNxgZsMit/53NAOLbq61YQ74jYCAa4joo/ ey0X2PQZ3/3bm+E2cXWSpB6hZO/jTrBThbP3qGkLWOm+drqXBg4pgso6Vs4MfFTbC0 aQ8/R/i1XmqrQ0wzuDa9JOYc9Pijwojwqhkz6iMjLwSst1CdhkLZfwpx7A0abLj0OR jIzXGIoSk7eIgmDMC4dDMAinhV7rbczVnBDNyzHR40zjZ7b5AweouJzMkNNpk9gzY2 2bdVcv7qmMC4Sk5aXtoE1RHrKPG3SxsS3gDyo/I6z8Ch5IE/d7VZapDQceu4DQu2HL k0PE6a3W3ifGx77d4EQRpjHA= From: Manos Pitsidianakis Date: Tue, 05 May 2026 11:14:05 +0300 Subject: [PATCH RFC 5/6] rust: impl interruptible waits for Completion Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260505-rust-virtio-v1-5-9563383909e4@pitsidianak.is> References: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> To: Miguel Ojeda Cc: Manos Pitsidianakis , Peter Hilber , Stefano Garzarella , Stefan Hajnoczi , Viresh Kumar , "Michael S. Tsirkin" , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , rust-for-linux@vger.kernel.org, Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Manos Pitsidianakis X-Developer-Signature: v=1; a=openpgp-sha256; l=2093; i=manos@pitsidianak.is; h=from:subject:message-id; bh=kgKzIAsgVjpYWlipSjiAGnVMQwoh2Eyh3sSKdi6XpN8=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnArYWJVUVZ2Y0t0c2hKMEpZR2NlZm0zd0VFN09KCnp0TE56ZzQxQkliRzFmbCt4 RENKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWZtbTFBQUt DUkIzS2Nkd2YzNEowTUNrRC85YnZobERZZGpCZGZJbU14aGdjeXkrU24yQk5IUG5JUmw4ZUxuVA pNRTByNCtZeGJ0UG5iMDJnZzdWc0Z6RkNXVnFoalVFc1haVEx2cWxtTjN1Q2V2V1dLeC9ZNHdQT 1lieHdHOWtBCmtqYlRyUkFVOU5HeW9YRm1OejAzcVJGQ254UjhOWmdTV1NjQ0p5VmJqMldnZUM3 U3M3bFhybyt3eXgyWkg0TjcKTnptNDVHb0wrazNCa25md2J6VVBSSHFRWWxMRWVwNmtOZ051WGp GK2wvd2dBYkhBeUVvL2g1SnVBbXRkNlMwTgp5QzV2WGFMeUwzNE9QSXlCQWdoQnFWYSsrcnU2R0 RPZkY5MXVVUTRjL2gySUhhcTlYa2ZHNGhHa01RcldOWmtjCllEVTUrNVZXZkFIdXo4YTA5aUEzT TlhZ1FpWXRjZXlXSzJCQzhDMStvVWxwZVVSSlB4bzJmREZtYWtESXYvY08Kbk5VMVF5akhBQ0ZP RUFiU3dtZC8xZTFoRXd5dFhSY1hlOFU2N3BrcHo3Q2Fqb1RkTkFCOU5oaWJaRkcvM09qUQpMbGh Ob3BOVk1yV0didGZEMC85aFhrQ0xTYkJDSlhRcHJrWjdyZlJwaWVrSVE5K29tRklyZGxnVnJGdm 4wc1VoCnZmS2FLaDV3anhESjhKVkFyd0RHRlRiN21xZWxlSk1VK3cvYUZFRVBmTFdYbGd6ODh4K 1JBYUtsUjdWYWdIQ04KZlp6akxEM2pXVy84ZTg3MnQwaGZZbVE1Y1ZBU3phT0VCZzhxQ0RQNDBj aU9VbEdsa0IxckcrNlIyWkF4Ti9KZwpvWE9BaW94Qk8wYzZJdC8zR3JGaWc3UHQwS2JuTjRrSEZ Fc0FwYnBBOVI3eElGVnZZajQxVC9JRUxzR2VRcFF1Ck9yVkN4QT09Cj1TOFFlCi0tLS0tRU5EIF BHUCBNRVNTQUdFLS0tLS0K X-Developer-Key: i=manos@pitsidianak.is; a=openpgp; fpr=7C721DF9DB3CC7182311C0BF68BC211D47B421E1 Allow Completion to wait interruptibly. Signed-off-by: Manos Pitsidianakis --- rust/kernel/sync/completion.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/rust/kernel/sync/completion.rs b/rust/kernel/sync/completion.rs index c50012a940a3c7a3e0edf302c8f833bdc4415200..958e26f00a8e645ab080cb5d852= 9e31ac3042dd0 100644 --- a/rust/kernel/sync/completion.rs +++ b/rust/kernel/sync/completion.rs @@ -109,4 +109,43 @@ pub fn wait_for_completion(&self) { // SAFETY: `self.as_raw()` is a pointer to a valid `struct complet= ion`. unsafe { bindings::wait_for_completion(self.as_raw()) }; } + + /// Wait for completion of a task. + /// + /// This method waits for the completion of a task; it is not interrup= tible and there is no + /// timeout. + /// + /// See also [`Completion::complete_all`]. + pub fn wait_for_completion_interruptible(&self) -> Result { + // SAFETY: `self.as_raw()` is a pointer to a valid `struct complet= ion`. + let err =3D unsafe { bindings::wait_for_completion_interruptible(s= elf.as_raw()) }; + if err < 0 { + Err(Error::from_errno(err)) + } else { + Ok(()) + } + } + + /// Wait for completion of a task. + /// + /// This method waits for the completion of a task; it is not interrup= tible and there is no + /// timeout. + /// + /// See also [`Completion::complete_all`]. + pub fn wait_for_completion_interruptible_timeout( + &self, + timeout_jiffies: c_ulong, + ) -> Result { + // SAFETY: `self.as_raw()` is a pointer to a valid `struct complet= ion`. + let ret: c_long =3D unsafe { + bindings::wait_for_completion_interruptible_timeout(self.as_ra= w(), timeout_jiffies) + }; + if ret =3D=3D 0 { + Err(ETIMEDOUT) + } else if ret < 0 { + Err(Error::from_errno(ret as c_int)) + } else { + Ok(ret) + } + } } --=20 2.47.3 From nobody Sun Jun 14 00:17:47 2026 Received: from mail.nessuent.net (mail.nessuent.net [188.245.177.90]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE7A03ED104; Tue, 5 May 2026 08:14:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=188.245.177.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968866; cv=none; b=q/zgGNuXS5IXw1zKQRUL+e5XB3Y3MGzcx5VJVAum+ZmS8KWPeS+PdcQo8YQ1VZLImO6kz6nrCELh1+a+zI3PT/VpHz2rTsV99x5jFnXWkXwcHxsIPzE7HcsPC9o1R1Ldc86xwKWAxT0+QDodKBmhX/Et7D/HCU97a7sImVzvPEU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777968866; c=relaxed/simple; bh=BYgTqREyMI9WYljSQMXSgvWtXjCniX5hGlYc44CoHNw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tlrwOxWh/WMxF2PS7hZeUtR6Fs3ysqlOkrEzdxsXydxUyOE4pQ4ladHcfkY+1uAKKApGPNoKL7HeiXFwyZR07S0yiE7xH3oC3pOStmKp9/kQ1svvPYKNvBbq8NMhalX8pnd/hvtwcM4vaCFUzw/MieI98Wv4AhVJhtQx/2DfsUw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is; spf=pass smtp.mailfrom=pitsidianak.is; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b=Sbk98eBi; arc=none smtp.client-ip=188.245.177.90 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pitsidianak.is Authentication-Results: smtp.subspace.kernel.org; dkim=pass (4096-bit key) header.d=pitsidianak.is header.i=@pitsidianak.is header.b="Sbk98eBi" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1777968862; bh=BYgTqREyMI9WYljSQMXSgvWtXjCniX5hGlYc44CoHNw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=Sbk98eBiwukmeKCKRhf/mc1SLG+znRXw3Tz5RzIkNtTdecf2kCmvtJS5TvxzD+Lee 6J+M+aZsn7q8Vm8GyyvfEKHTHfDf0cm+oDCacNzDH2pwM/8SUR6gpVIjKhqWclrWAh ER6P+70hC0hqSX3AjDa5hTuKtQG690TpiEYsxkgYp/+FyrF5UtSRhxtA2obcZcWk6G xBBX1otPszwaPy+JfgjlHmV7uSgyR18OEVRllT9dDX5AOgETCaiFYbnNj/kjx2fjKg KAD6s5R2B++HOtkkDwGI6wHCwQq5J8wxcI2HGv3hXFtApeHo9TzUMgVlb8fCgRV0J9 Wy/5N6WG1TOOgU6okv+1tVzMwacAikUtz1Ihnt3mme9BXTnDMm9JP6bgtUVBb4h04p 8CT4xvpDqdijqqMQvMDlSPjmLSBNP3LccaAxCX8Rx2OsjH61pvKaxh2OQpz3NrXguj d/mdOBySuYETJLQd2pBwSr7jSecEm809oSxOivGpwFIUI9F+7Z+QMIgVLRVKTzdJJe sPXWACfs4UCOMYM8b572IRv3mP3Ehq3kY73/1DTnzatJq5Jt1SUDElaDRakehLGpao jd9II2k/RMBn1zHXJjybKk0JFtxbZqfYkdGs/gXj06eTQq9xeXCvmCIhfepLcVaaJW OlYVWFM1WUdhZwFyEZpdrn+c= From: Manos Pitsidianakis Date: Tue, 05 May 2026 11:14:06 +0300 Subject: [PATCH RFC 6/6] samples/rust: Add sample virtio-rtc driver [WIP] Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260505-rust-virtio-v1-6-9563383909e4@pitsidianak.is> References: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> In-Reply-To: <20260505-rust-virtio-v1-0-9563383909e4@pitsidianak.is> To: Miguel Ojeda Cc: Manos Pitsidianakis , Peter Hilber , Stefano Garzarella , Stefan Hajnoczi , Viresh Kumar , "Michael S. Tsirkin" , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , rust-for-linux@vger.kernel.org, Jason Wang , Xuan Zhuo , =?utf-8?q?Eugenio_P=C3=A9rez?= , virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, Manos Pitsidianakis X-Developer-Signature: v=1; a=openpgp-sha256; l=17519; i=manos@pitsidianak.is; h=from:subject:message-id; bh=BYgTqREyMI9WYljSQMXSgvWtXjCniX5hGlYc44CoHNw=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnArYWJVUzZNWUFSemxnb2IxNllHZ1JCVlllNEZtCm9QZExnZzE4aGdMdXNHWktl OE9KQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWZtbTFBQUt DUkIzS2Nkd2YzNEowSk93RC85RXdjRnk5RmRROU1yeTU0dWU3U2g1NmQ3NS9wcjlMYkhaMW9CbA pwRmxKU0FyYzhaWVNwUlFMQS9XU3dqbEJEWmxwekZySFRJU2pMdG92ZUJyU0ZPTXJlVzZaS00vZ XpId2JyZmkzCnhBWWM4TjYxU3M5eStXaUxuVVhGVi9XMjZmNVRjdHBja2d1TUtDVHhNTzVmbkQv VkhhMEl3dWZ2UWQ2OVc3eWoKOG9wdkw1ZU1jZTBvcWFJK0xDREYwYitxd3k5dy9rdnNIWUh6cmZ GbXc5QjdlcldzM3NkNHAzTjNZaTRBN0gwSwoxaHA3Rzg1SWE3WFVVZ1ZMV1lHREh1YzdmK1ZaMn FkdDUwbGFGb3M4YllsRXl0UVdyeHBUalQ2YS9hVmx3K2lGCllMUTlMUmRNS1lNMk52dGlzcnJmW kNUODNPKzR3Ym13NnMyVHFDNDQzVzY2WSs5VGNFN2REcEp4YTJSMWNuZ3YKT25IdlhWeWtLYWlR cEptS0FtQzlzOXZ4UWpOSk9TWHNLUEhydnJSMFBZN1BFUDFJMjQ5YTVrMjRLMlZvM0xsOQpXTDd tUVY3Qzg0NmFYbnRaUzVkOXJDNEU3bU1sYTJucy9EekorbjN6SjhyeW9TSHM0MDVRNDJuSVlXV3 RXSy9TCituODhmSTRVS2tDelRRL1lXNlpzQlBxL3RRd2d0S2E5MkVhbWt6MFljT0N1VVZBV0cyK zJJMmlnVWRjMWJHNDcKYVdTckhZSmRjdGJXQVprQ2M0Y3RMWXUzNkJ3SFZxUktPWnNhalV4ZEFP T0FJQm96MGIwMHRLR3RCOW5hR1puTApjbWZIcVVHZjZITXVwT3llU0pYVWcrMXdKN2NScXE5UWQ 2VzloOEY0QytJZFpTLzNKRFFTaGpGZkFhbEdMbVJOCnRxMFpIdz09Cj1Fdy9RCi0tLS0tRU5EIF BHUCBNRVNTQUdFLS0tLS0K X-Developer-Key: i=manos@pitsidianak.is; a=openpgp; fpr=7C721DF9DB3CC7182311C0BF68BC211D47B421E1 While the driver queries clocks and capabilities for each clock, it doesn't actually register them yet (TODO). Until I implement missing functionality, there is some dead code and some missing SAFETY comments. Signed-off-by: Manos Pitsidianakis --- MAINTAINERS | 1 + samples/rust/Kconfig | 15 ++ samples/rust/Makefile | 1 + samples/rust/rust_virtio_rtc.rs | 470 ++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 487 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e8012f708df5d4ee858c82aec3269e615fc8caad..3ed579e8d3cc64d1749cf261cd6= 8f6338a830c4d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27937,6 +27937,7 @@ S: Maintained F: rust/helpers/virtio.c F: rust/kernel/virtio.rs F: rust/kernel/virtio/ +F: samples/rust/rust_virtio_rtc.rs =20 VIRTIO CRYPTO DRIVER M: Gonglei diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index c49ab910634596aea4a1a73dac87585e084f420a..96a16aecc27198fd99f4ffd0ecd= f0bc0876860c6 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -179,4 +179,19 @@ config SAMPLE_RUST_HOSTPROGS =20 If unsure, say N. =20 +config SAMPLE_RUST_VIRTIO_RTC + tristate "Rust Virtio RTC driver" + depends on VIRTIO + depends on PTP_1588_CLOCK_OPTIONAL + help + This driver provides current time from a Virtio RTC device. The driver + provides the time through one or more clocks. The Virtio RTC PTP + clocks and/or the Real Time Clock driver for Virtio RTC must be + enabled to expose the clocks to userspace. + + To compile this code as a module, choose M here: the module will be + called rust_virtio_rtc. + + If unsure, say M. + endif # SAMPLES_RUST diff --git a/samples/rust/Makefile b/samples/rust/Makefile index 6c0aaa58ccccfd12ef019f68ca784f6d977bc668..0142fd8656bb8cdc95b7ef54e31= 83b5e51358954 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) +=3D rust_driver_f= aux.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) +=3D rust_driver_auxiliary.o obj-$(CONFIG_SAMPLE_RUST_CONFIGFS) +=3D rust_configfs.o obj-$(CONFIG_SAMPLE_RUST_SOC) +=3D rust_soc.o +obj-$(CONFIG_SAMPLE_RUST_VIRTIO_RTC) +=3D rust_virtio_rtc.o =20 rust_print-y :=3D rust_print_main.o rust_print_events.o =20 diff --git a/samples/rust/rust_virtio_rtc.rs b/samples/rust/rust_virtio_rtc= .rs new file mode 100644 index 0000000000000000000000000000000000000000..f580ed83a0a57a4b051372a51f5= 6b787d53ed602 --- /dev/null +++ b/samples/rust/rust_virtio_rtc.rs @@ -0,0 +1,470 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust virtio driver sample. + +use core::{ + cell::Cell, + marker::PhantomData, + ptr::NonNull, // +}; + +use kernel::{ + device::{ + Core, + CoreInternal, // + }, + new_mutex, new_spinlock, page, + prelude::*, + scatterlist::SGEntry, + sync::Completion, + sync::{Mutex, SpinLock}, + virtio::{ + self, + utils::*, + virtqueue::*, // + }, +}; + +use pin_init::stack_try_pin_init; + +#[pin_data] +struct Token { + resp_actual_size: u32, + #[pin] + responded: Completion, +} + +#[pin_data] +struct Message { + msg_type: u16, + #[pin] + req: KVec, + #[pin] + resp: KVec, + req_ptr: NonNull, + resp_ptr: NonNull, + #[pin] + token: Token, + _ph_req: PhantomData, + _ph_resp: PhantomData, +} + +#[derive(Copy, Clone, Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_req_head")] +struct ReqHead { + msg_type: Le16, + reserved: [u8; 6], +} + +#[derive(Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_resp_head")] +struct RespHead { + status: u8, + reserved: [u8; 7], +} + +#[derive(Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_resp_cfg")] +struct RespCfg { + head: ReqHead, + /** # of clocks -> clock ids < num_clocks are valid */ + num_clocks: Le16, + reserved: [u8; 6], +} + +#[derive(Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_req_clock_cap")] +struct ReqClockCap { + head: ReqHead, + clock_id: Le16, + reserved: [u8; 6], +} + +#[derive(Copy, Clone, Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_resp_clock_cap")] +struct RespClockCap { + head: ReqHead, + clock_type: u8, + leap_second_smearing: u8, + flags: u8, + reserved: [u8; 5], +} + +#[derive(Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_req_read")] +struct ReqRead { + head: ReqHead, + clock_id: Le16, + reserved: [u8; 6], +} + +#[derive(Copy, Clone, Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_resp_read")] +struct RespRead { + head: ReqHead, + clock_reading: Le64, +} + +#[repr(u8)] +enum ClockType { + #[doc(alias =3D "VIRTIO_RTC_CLOCK_UTC")] + Utc =3D 0, + #[doc(alias =3D "VIRTIO_RTC_CLOCK_TAI")] + Tai =3D 1, + #[doc(alias =3D "VIRTIO_RTC_CLOCK_MONOTONIC")] + Monotonic =3D 2, + #[doc(alias =3D "VIRTIO_RTC_CLOCK_UTC_SMEARED")] + UtcSmeared =3D 3, + #[doc(alias =3D "VIRTIO_RTC_CLOCK_UTC_MAYBE_SMEARED")] + UtcMaybeSmeared =3D 4, +} + +// SAFETY: `Message` is safe to be send to any task. +unsafe impl Send for Message {} + +// SAFETY: `Message` is safe to be accessed concurrently. +unsafe impl Sync for Message {} + +impl Message { + /// Create an initializer for a new [`Message`]. + fn new(req_data: Request, msg_type: u16) -> Result> { + macro_rules! alloc_buf { + ($t:ty) =3D> {{ + let size =3D (core::mem::size_of::<$t>() / page::PAGE_SIZE= + 1) * page::PAGE_SIZE; + KVec::::with_capacity(size, GFP_KERNEL) + }}; + } + let mut req =3D alloc_buf!(Request)?; + let mut resp =3D alloc_buf!(Response)?; + let req_ptr: NonNull =3D NonNull::new(req.as_mut_ptr().ca= st()).unwrap(); + let resp_ptr =3D NonNull::new(resp.as_mut_ptr().cast()).unwrap(); + // SAFETY: `req_ptr` is a valid Request allocation + unsafe { + core::ptr::write(req_ptr.as_ptr(), req_data); + } + Ok(pin_init!(Self { + req, + resp, + msg_type, + req_ptr, + resp_ptr, + token <- pin_init!(Token { + resp_actual_size: 0, + responded <- Completion::new(), + }), + _ph_req: PhantomData, + _ph_resp: PhantomData, + }? Error)) + } + + fn get_response(&self) -> Result<&Response, Error> { + if self.token.resp_actual_size as usize !=3D core::mem::size_of::<= Response>() { + if self.token.resp_actual_size as usize >=3D core::mem::size_o= f::() { + let head: &RespHead =3D unsafe { self.resp_ptr.cast().as_r= ef() }; + return match head.status { + 0 | 3 =3D> Err(EINVAL), + 1 =3D> Err(ENOTSUPP), + 2 =3D> Err(ENODEV), + 4 | 5_u8..=3Du8::MAX =3D> Err(EIO), + }; + } + return Err(EINVAL); + } + Ok(unsafe { self.resp_ptr.as_ref() }) + } + + fn send(&self, vq: &SpinLock, timeout_jiffies: c_ulong) -= > Result { + let guard =3D vq.lock(); + + let mut sg_in =3D core::mem::MaybeUninit::zeroed(); + let mut sg_out =3D core::mem::MaybeUninit::zeroed(); + let req =3D unsafe { + SGEntry::init_one( + &mut sg_out, + self.req_ptr.cast(), + core::mem::size_of::() as u32, + ) + }; + let resp =3D unsafe { + SGEntry::init_one( + &mut sg_in, + self.resp_ptr.cast(), + core::mem::size_of::() as u32, + ) + }; + let sgs =3D [req, resp]; + guard.as_ref().add_sgs( + &sgs, + 1, + 1, + (&raw const self.token).cast_mut().cast(), + GFP_ATOMIC, + )?; + + if guard.as_ref().kick_prepare() { + guard.as_ref().notify(); + } + drop(guard); + + if timeout_jiffies > 0 { + self.token + .responded + .wait_for_completion_interruptible_timeout(timeout_jiffies= )?; + } else { + self.token.responded.wait_for_completion_interruptible()?; + } + Ok(()) + } +} + +// TODO: use a proper enum + +const VIRTIO_RTC_REQ_READ: u16 =3D 0x0001; +const VIRTIO_RTC_REQ_CFG: u16 =3D 0x1000; +const VIRTIO_RTC_REQ_CLOCK_CAP: u16 =3D 0x1001; + +struct VirtioRtcVq { + ptr: NonNull, +} + +// SAFETY: `VirtioRtcVq` is safe to be send to any task. +unsafe impl Send for VirtioRtcVq {} + +impl VirtioRtcVq { + fn new(ptr: *mut Virtqueue) -> impl PinInit> { + let ptr =3D NonNull::new(ptr).unwrap(); + new_spinlock!(Self { ptr }) + } + + fn as_ref(&self) -> &Virtqueue { + unsafe { self.ptr.as_ref() } + } +} + +struct VirtioRtcDriver { + reqvq: Pin>>, + alarmvq: Option>>>, + num_clocks: Cell, + registered_clocks: Pin>>>, +} + +impl Drop for VirtioRtcDriver { + fn drop(&mut self) { + pr_info!("Remove Rust virtio driver sample.\n"); + } +} + +unsafe extern "C" fn vq_requestq_callback(vq: *mut kernel::bindings::virtq= ueue) { + let vq =3D unsafe { Virtqueue::from_raw(vq) }; + let dev: &virtio::Device =3D vq.dev(); + let data =3D unsafe { dev.as_ref().drvdata_borrow::()= }; + data.process_requestq(); +} + +impl VirtioRtcDriver { + /// Submit `VIRTIO_RTC_REQ_CFG` and return response (`num_clocks`) + fn req_cfg(&self) -> Result { + let head =3D ReqHead { + msg_type: VIRTIO_RTC_REQ_CFG.into(), + reserved: [0; 6], + }; + stack_try_pin_init!( + let msg: Message:: =3D + Message::new(head, VIRTIO_RTC_REQ_CFG)?); + let msg: core::pin::Pin<&mut Message> =3D msg?; + msg.send(&self.reqvq, 0)?; + pr_info!("Got response! {:?}\n", msg.get_response()); + + let response: &RespCfg =3D msg.get_response()?; + Ok(response.num_clocks.into()) + } + + fn process_requestq(&self) { + let mut cb_enabled =3D true; + loop { + let guard =3D self.reqvq.lock(); + if cb_enabled { + guard.as_ref().disable_cb(); + cb_enabled =3D false; + } + if let Some((token, len)) =3D guard.as_ref().get_buf() { + drop(guard); + pr_info!("process_requestq got buf {len} bytes\n"); + let mut token =3D token.cast::(); + + unsafe { token.as_mut().resp_actual_size =3D len }; + unsafe { token.as_mut().responded.complete_all() }; + } else { + if guard.as_ref().enable_cb() { + return; + } + cb_enabled =3D true; + } + } + } + + fn clock_cap(&self, clock_id: u16) -> Result { + type ClockCapMsg =3D Message; + + let req =3D ReqClockCap { + head: ReqHead { + msg_type: VIRTIO_RTC_REQ_CLOCK_CAP.into(), + reserved: [0; 6], + }, + clock_id: clock_id.into(), + reserved: [0; 6], + }; + stack_try_pin_init!( + let msg: ClockCapMsg =3D Message::new(req, VIRTIO_RTC_REQ_CLOC= K_CAP)? + ); + let msg: core::pin::Pin<&mut ClockCapMsg> =3D msg?; + msg.send(&self.reqvq, 0)?; + pr_info!("Got response! {:?}\n", msg.get_response()); + let response: &RespClockCap =3D msg.get_response()?; + Ok(*response) + } + + fn read(&self, clock_id: u16) -> Result { + type ReadMsg =3D Message; + + let req =3D ReqRead { + head: ReqHead { + msg_type: VIRTIO_RTC_REQ_READ.into(), + reserved: [0; 6], + }, + clock_id: clock_id.into(), + reserved: [0; 6], + }; + stack_try_pin_init!( + let msg: ReadMsg =3D Message::new(req, VIRTIO_RTC_REQ_CLOCK_CA= P)? + ); + let msg: core::pin::Pin<&mut ReadMsg> =3D msg?; + msg.send(&self.reqvq, 0)?; + pr_info!("Got response! {:?}\n", msg.get_response()); + let response: &RespRead =3D msg.get_response()?; + Ok(response.clock_reading.into()) + } +} + +impl virtio::Driver for VirtioRtcDriver { + type IdInfo =3D (); + + /// The table of device ids supported by the driver. + const ID_TABLE: virtio::IdTable =3D &VIRTIO_RTC_TABLE; + + fn probe(vdev: &virtio::Device) -> impl PinInit { + const VQS_INFO: [VirtqueueInfo; 1] =3D [ + VirtqueueInfo::new(c"requestq", false, vq_requestq_callback), + //VirtqueueInfo::new(c"alarmq", false, vq_callback), + ]; + let init_fn =3D move |slot: *mut Self| { + pr_info!("Probe Rust virtio driver sample.\n"); + let vqs =3D match vdev.find_vqs(&VQS_INFO) { + Ok(vqs) =3D> { + pr_info!("Found {} vqs.\n", vqs.len()); + vqs + } + Err(err) =3D> { + pr_info!("Could not find vqs: {err:?}.\n"); + + return Err(err); + } + }; + let reqvq =3D KBox::pin_init(VirtioRtcVq::new(vqs[0]), GFP_ATO= MIC)?; + let registered_clocks =3D + KBox::pin_init(new_mutex!(KVec::with_capacity(0, GFP_KERNE= L)?), GFP_KERNEL)?; + unsafe { + core::ptr::write( + slot, + Self { + num_clocks: Cell::new(0), + reqvq, + alarmvq: None, + registered_clocks, + }, + ) + }; + Ok(()) + }; + unsafe { pin_init::pin_init_from_closure(init_fn) } + } + + fn init(&self, vdev: &virtio::Device) -> Result { + vdev.ready(); + self.num_clocks.set(self.req_cfg()?); + for i in 0..(self.num_clocks.get()) { + let mut is_exposed =3D false; + + let resp =3D self.clock_cap(i)?; + let (clock_type, leap_second_smearing, flags) =3D + (resp.clock_type, resp.leap_second_smearing, resp.flags); + if cfg!(CONFIG_VIRTIO_RTC_CLASS) + && (clock_type =3D=3D ClockType::Utc as u8 + || clock_type =3D=3D ClockType::UtcSmeared as u8 + || clock_type =3D=3D ClockType::UtcMaybeSmeared as u8) + { + // TODO: + + // ret =3D viortc_init_rtc_class_clock(viortc, vio_clk_id, + // clock_type, flags); + // if (ret < 0) + // return ret; + // if (ret > 0) + // is_exposed =3D true; + dev_warn!(vdev.as_ref(), "CONFIG_VIRTIO_RTC_CLASS TODO "); + } + + if cfg!(CONFIG_VIRTIO_RTC_PTP) { + // TODO: + + // ret =3D viortc_init_ptp_clock(viortc, vio_clk_id, cloc= k_type, + // leap_second_smearing); + // if (ret < 0) + // return ret; + // if (ret > 0) + // is_exposed =3D true; + // todo!() + dev_warn!(vdev.as_ref(), "CONFIG_VIRTIO_RTC_PTP TODO "); + } + + if !is_exposed { + dev_warn!( + vdev.as_ref(), + "cannot expose clock {i} (type {clock_type}, variant {= leap_second_smearing}, \ + flags {flags}) to userspace\n" + ); + } + let clock_reading =3D self.read(i)?; + pr_info!("#{i} clock reading =3D {clock_reading}\n"); + } + Ok(()) + } + + fn remove(vdev: &virtio::Device, _this: Pin<&Self>) { + pr_info!("Removing Rust virtio driver sample.\n"); + vdev.reset(); + vdev.del_vqs(); + } +} + +kernel::virtio_device_table!( + VIRTIO_RTC_TABLE, + MODULE_VIRTIO_RTC_TABLE, + ::IdInfo, + [(virtio::DeviceId::new(virtio::VirtioID::Clock), ())] +); + +kernel::module_virtio_driver! { + type: VirtioRtcDriver, + name: "rust_virtio_rtc", + authors: ["Manos Pitsidianakis"], + description: "Rust virtio driver", + license: "GPL v2", +} --=20 2.47.3