From nobody Sat Jun 13 04:51:51 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 ED58A35AC1E; Sun, 10 May 2026 13:38:42 +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=1778420331; cv=none; b=qp8CFrgPLSpTpLmSUt4wZxBG5R0fgR6Rx3W3+wOUfizpnqS1R3/yKQ0VFxY6En6T+x0WKOWTwVnesZnUIFQsB3CJtpbnlio0+VRm1ovzRtbggutTiuaF2OFW5T2nQEVuM4TvctbUP4NYhcD95fE/4WvIxzXtqYkfWMEkKMGKPjQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778420331; c=relaxed/simple; bh=jbzi2Emj0Xf9BmoPlY0PU4j/8PVZ/5uK5OX2z0vqwIQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YDW4rKRXEMjmu1ZkfUXqolNxUfyvzc7ZIxQszC0aOJkhooMNQngoPx4Ee1/61twtLPe9ma9Y3i6dWnn6Fe13TPLKlhpmSDyV09aM3+YeoUP3XfbAaT8BEwaakjrA6HgdwAi1ktdQFTYyISj2yqwnD5/SDpTKdCuHThYG61K/J8o= 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=jJIMakZc; 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="jJIMakZc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1778420311; bh=jbzi2Emj0Xf9BmoPlY0PU4j/8PVZ/5uK5OX2z0vqwIQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=jJIMakZcxlbV8Ybl4Auad0TDT3lBvL/RKO9V6WwdXme2Q2hfootp44qFASSeyHSOq jyQmYPxwz7HOYwtq9ExGlA0L6CoV5ILOTCWUb63qrPtrBjHNpBjLtcrPl8gv6BXSHD IEWNShN3D3yYl8F449fexjjLsUaZ9/zhum4ckwNClZyq5RiQvcqJUnYFRfxQy5okJh OwDCZupK9Kjee5k+bwqFrcR62w0cNbAEQXQkEsWmradN9+91skF0arltt5C0IA8Ojh M3FdzyayIlSzUkxwB8PbMsRBcyTRS22eVSF6flFdkxkM35dg1pP+gDSTWU40uGELLX 1ium59N5c1NYF6kNTT/+VzBQP71t/7MQkOZWF9I83epv7hMgTJO5EK5BNJ70Fo4efd gtLm27J3RPZw92pX62HZYrMQIg/eE2cl0wluIXNv5j1oVu0ZzM/n6az4nRrtGsVPae hgRJkuJyeeFscR4isjOQjJ5pIJ68ksO/uDZMGo0ktSWU0BvMdi6zOL2YO8o+n4ECWJ hC6XFqXVpgUxO6rXFJtO126tn8AgXcgE3HtsI0iQvNTQiFDgpGIWsRdPuqPP+gPBsi Wr/g5mD1qY1a4GoZoWImMvwEXH5gGlnwVVDcWXPkfqFn40jHtiUth7L+anN51ZRd7W 8b21CzZyocL89UtLm9gqUr/w= From: Manos Pitsidianakis Date: Sun, 10 May 2026 16:38:14 +0300 Subject: [PATCH RFC v3 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: <20260510-rust-virtio-v3-1-1427f14d67e1@pitsidianak.is> References: <20260510-rust-virtio-v3-0-1427f14d67e1@pitsidianak.is> In-Reply-To: <20260510-rust-virtio-v3-0-1427f14d67e1@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 , Daniel Almeida , 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=834; i=manos@pitsidianak.is; h=from:subject:message-id; bh=jbzi2Emj0Xf9BmoPlY0PU4j/8PVZ/5uK5OX2z0vqwIQ=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnFBSXBSZk1GbzVEdFd3eWc3WEIrOSt5elYvbTR3CkJjSzZnSkZLVFptbUY4OHhi dWVKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWdDS1VRQUt DUkIzS2Nkd2YzNEowSm5SRC85WVFtdlhCTDl5a21iRXhhMTVHZ21odlNWRERSNVYwa1duUk01Vg o2ZUFFeE9YWm1BK0t5eUhRNEFLellIdHBXS25hbjVwT01NcTI2YkhobTJHTUlFUVRlc2hRYnVwa DBKbC9VTktQCno0anFUVUlKRkc4MTRzR0hGdEZFUi93L1pNMWJiOW9mMVlJL3JpT0xta1RFbDRM ZVFwNE9GN2h6WTV5aXllRW4KTjdhNDhuOU1wVnkwbTE0THdTcWlLOEloQ3gycUJFTG9wUDdjOFF yM1FqWloyOHhzdjk5WGxEZUxkRkxaNHdSbApwZm9yU3JKaHNBQ2JkcWRkeUFJOEVwUURTb1Uwdl BZNGxGMUYvT1B2RE4ydzhFWkloWGFHTXBGRG5XUG0yODJZClJ4Y1RmK1h1N0dsTDNXWERWYkVEb VVHaGJwVk9jb3JRUldLZkxGSmFQZitTWUd6Q2h1UXU1WGF2U2dYVkZSVzgKZGtycWZTMXN2K29R SFFTR1hnVkVzQytZT1dPZ3VqbWk4SXQ1ak55SlV0dVUwNDUxT1RhdEhUQ0pBWVFCdmtOYgpkTDB BYVRQbGJ1UjhrcTV4cjlIRUQ0VlZhbTdOQ0Z6UkFySEFjaWd1ZVJzQStURGlBM2tpYVMzTzhIWU I5eE1hClZ5S0hpQnBmOHNGZ3YyemlwU01zNDZJWmFYajM1WUNyRXB3Nk9BUW5DQkIwc0tjdDVyS HF5TzluY3d0bWZsVk8KaGNTK1EyZ1dGSmd4RDl6bDBKZzVOYVFRVzhETlEwZkpDdXNHcStVZnRN RnhXRjJzZVZjWjJzMjEvdmRJVnZobApoRStSTi9KUjlBSTZLaHk2UTVOSTQxdXhPTGxhcm5YdVh LVjVhcjRST0VSM29UNWdyMnJpWVo1UVU5WkpHQUJHCkVXaFFSdz09Cj1xQ0dxCi0tLS0tRU5EIF 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..1cbe1a4b5647fd646c1be3c5c80= fb24ae7b97a4a 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 IS_ENABLED(CONFIG_VIRTIO) +#include +#include +#endif /* IS_ENABLED(CONFIG_VIRTIO) */ --=20 2.47.3 From nobody Sat Jun 13 04:51:51 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 1CB2C390218; Sun, 10 May 2026 13:38:48 +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=1778420346; cv=none; b=A9Z+6pgQQC0zXcYC/5xR8eIcq58XCO9QdWMURyLiBjx8CvwHlQ6ObN2a4df8Fyz7cAIDQ/dmHIMCEz7P549wHy5EMicdZtX7EDt3wWYu8NGP3c8p3TNkIx+ThngWfWpqsE5Vak9whZW3QJ6KW4PFgc8CqlRKHa5CLwT44uH15Dg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778420346; c=relaxed/simple; bh=i7U7k/F42Bi8LpEeWcbtiwQlBBwyKe9OTJzHbVwvb/c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=gWiCLNPLCK1eqMzzIZRsHunBJsF+n3g3VE3eF7UTIz0fkrgkdM6xYNcOYx/ym85NdSS4iGtZbY+3pP15UWyXea4zgJLdr5QZrun8bOE/QFiRPTSeBJjP/FAfSpydsvxS5Zm+DQCp6LSF5CZSddOrNrIjmXpF0lvi0NKeaWO9C5A= 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=xhgt/7uP; 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="xhgt/7uP" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1778420313; bh=i7U7k/F42Bi8LpEeWcbtiwQlBBwyKe9OTJzHbVwvb/c=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=xhgt/7uPTBLZdK25GhmRTIRjlm57rGAGDmmGFaJKfTmtPFWzr1tAnHEU21RwaFiEy Hz7p+6xlSlII80NLpmsyKebmzv5LiGUcUSRQR6Ps932zUrnjoGxIBsb469cC/mRTEn YuZz+BCzFNL8s3cO7jW1dl7R4TNxtkv7RZnF9wRonqDe0WJdmQX0l85+vBavn+Ci7B 74RdQQCSg/nmIMztsNULkkoek2J9OaHDDNIO60TaC58SYDqZYhptPXJt+gKcyDRSYj +QDBRzfcCCYzWkkPMxToTq55z7XU5UC9PXmrh3a5arxLVh/HFf1D8+3vScY0ZJqEJc 4le8uM4LTKoqr7kjRmUEcgpH5KLYRjVbxEmo+OBb88ddNq8QlSseh89CKgHJT0ovzH zIjCxFUn7wzxIF+KtrQGXLr2AMZn9iiqNpOZz/v6OKOqQUiOkDtYsKLM7cAF4C0o+u YiCJLB2qzm8ki6EQZt1mYC9eXjReOLZnTP3L70Zc14DkOKLWriumPUYkGrD3g8DTxd jSxG2HoCLYD3d8TCCL/gaZvan/zUmDV1gZFdwTv6S1WbehecHAey4zUcMxmbHDgWA1 23/Ux+dokboyZnUeUAN6HFNXPPSoL5ja2aXfaGo4/4HbNG1DP3XhE6b9rTvYdt/U27 yVoFB8QbiC95ZT7FolT3hOMw= From: Manos Pitsidianakis Date: Sun, 10 May 2026 16:38:15 +0300 Subject: [PATCH RFC v3 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: <20260510-rust-virtio-v3-2-1427f14d67e1@pitsidianak.is> References: <20260510-rust-virtio-v3-0-1427f14d67e1@pitsidianak.is> In-Reply-To: <20260510-rust-virtio-v3-0-1427f14d67e1@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 , Daniel Almeida , 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=2570; i=manos@pitsidianak.is; h=from:subject:message-id; bh=i7U7k/F42Bi8LpEeWcbtiwQlBBwyKe9OTJzHbVwvb/c=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnFBSXBTTGdCOW9kT2ZoZUdrR09pRCtQTlVEMndsCkZOYi9vVjlML1F1eXFBR0l6 R09KQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWdDS1VnQUt DUkIzS2Nkd2YzNEowQ0JORC93SlRKZ2xjOHZRN2RSOVp3Nk1JVVFtamRwMkxYOVlPQWhpL3VqTQ pMY2dJK3Q0OTFyc2E1QzdWYnRyaEJEQUxQT0JzMUg5R0lwSHFxb1FlL01YQjBhUFRlWHJBVHp5M ThXbkN4SkMvCjRsQ05zSWZZV09sSkdFRmxZclV0a1Rsc25idGZXWm9TbVQ3TGUyMVZhM0krKzVq cUpCa0tiVWQwdnVRdjd4TXkKV0pzcXBqc2dYSy82a3pYdXhkZ3BoWmI2VWk0Z3U3V2Y1eloxZnd qZWVTaWJrVnBvY2ttVGdaM0wvTzhZU0ZrUwp1Q0hqeEtLcDNFNzdLT2oxWU15THVFajBLTzhFdl hEWlVFZlVaSE1WcDFHV1ZicG11dWNEa2FvQklpM1p6WmJTCmNHdEVWbnNScUtkWVhkTG1oKzdhY Wx2YzdrRXFRN09yRGJWZ24wb01uajgrWFg2VmU2U1l1UnM5SGZoZFl5VW0KdkQ5VEIxMmZ3c1hQ RGhnTk12TE9GbFpuMG1LUkhYRTNDM3o3U1dKb1NCcUFFZkNMcENWNEFjQjFjL0lyUm43UQo0MHh pMVIxZVJ1VXBTTGRyQ2VjUU1la1lhQUM5bEcyamFHU0thSDIwM3dWdGxyZzVHTmxJUW83Z05NWH crQ3ExCmpvTmFNM0FQbjhyUGpRSlFEMkJncFhWYi8zcEhkQStzVTI0SXpjdC9aRWZCVFVjbUljQ zNWUDB1NW1HNTc1c0QKc3hKU2NZNEl3WHU5T2RBNXo2bXJ3N0lVdGdDa3NKUkMzanpURStOWmx1 VzFwOUs1U1RuRlR5Nm5JSFJRRmtvMgo5bEFxNmxRSXdmK3V3L3FGWDQzd1BVaDRoM1NHbmF1UjF CaUl4N1gyZStVSUc4VTVuaXhhaDdkN3BwTGFqL2QyCnFnWXVvUT09Cj1lNjR4Ci0tLS0tRU5EIF 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 --- MAINTAINERS | 6 ++++++ rust/helpers/helpers.c | 1 + rust/helpers/virtio.c | 37 +++++++++++++++++++++++++++++++++++++ 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..5dc0d2f2ee6bd2ae8e6abfe4baa= 247c1963967f6 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -61,6 +61,7 @@ #include "time.c" #include "uaccess.c" #include "usb.c" +#include "virtio.c" #include "vmalloc.c" #include "wait.c" #include "workqueue.c" diff --git a/rust/helpers/virtio.c b/rust/helpers/virtio.c new file mode 100644 index 0000000000000000000000000000000000000000..46aeeb063158823e66477777b3c= d4bd1525df330 --- /dev/null +++ b/rust/helpers/virtio.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifdef CONFIG_VIRTIO +#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); +} +#endif /* CONFIG_VIRTIO */ --=20 2.47.3 From nobody Sat Jun 13 04:51:51 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 D4572358373; Sun, 10 May 2026 13:38:37 +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=1778420320; cv=none; b=gNV8/iXPdPdg3BVjoH6YiKJ8lfi2CwCEy6D3d/s+IsqQdJCTqzlDHWDUQGLBCBIfSLQCgf7NvMDVc28L3NGLSrjH6jJ2jtWHUiyI4GTkJFGRHhsbQ/dROLdXRVJ8KwwbL6ZGbnGg97ZXY8fn+XEeTlAUBFx+Tw/o5QQ+8Lwuvwc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778420320; c=relaxed/simple; bh=hcTYlDg84gZsUt1opDAEy/hJk/exwjLlY5Z3TwHRPGc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qkUOgYrpkB+kgatrpyJW/80d084Ru+pWkDDVPpmYGHZWJ2q5/dpXNeuqessSG0mBszMMh1jMUAHtRFESkaUpA0fHFkj3NPWYiCznTscamnML890PWv4SBCs7DUOO1kRedU/y3jFBWbtFbN562SmPP3HTC+75/qV/R79z6BmkTf4= 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=tPEShpZz; 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="tPEShpZz" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1778420314; bh=hcTYlDg84gZsUt1opDAEy/hJk/exwjLlY5Z3TwHRPGc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=tPEShpZzjQzwhkTB5MUsoX4PaeYFzQAUxy2cjTA0rOJRhtsgzZDJYMiCxfshvDfj/ o3JQAs3vVh/nDvWQFhplIrC43zgmp6W0n2IlMsRiTD2sQonOXwW1uUzhCHlOZ+qurm qbq46DWamJfe5Esd8WoI9cVOkyQ2WR4j6aIV7ZKVB9/2PqUvfUKOmLNt8MQqGe6O52 EIDTIPS+jJKU9Zu5vaNIDzU5olAGZ9N6B33jbJrWGYuvWVPwnlMx1t7hFxquGURVxQ 3OCUBf6Y439S2UumliFY0Dy+y7aIVyaRQXAap/qv3jTRaMOzvclIZBw1MxXEm0u2oc JgRv51KXIU8nTu0aZeV/SY9R9qxqflbtPpepqFO3B7a4rAswO/YFLZZxVjYV+Wbh/W HAgKN49gzL5fuKi/KfVsjRzvGrrJ+6TPLrvXL19Q1mOyHr9LA02TeLAaqOkv3BsS3o vRaCpW1+AUPKLnjFfiovHGvW9DewWnsmOIiCByBOc4YQFDjdNjgzdplD8TZSTq2Ais P1X5eC6GKcBvMDNjF+hjcKPQ1hy3QivqLyR8XH9Eb4moawb3vhneFhebSZ6TBtGK6g EfjqG/Uqf1TpiLvup312PQwNk6mkyQLRmjBHle862poe45vXBxWIzzAkLLZris/sqE miFjup22BCzQY3P8A7fZTW/0= From: Manos Pitsidianakis Date: Sun, 10 May 2026 16:38:16 +0300 Subject: [PATCH RFC v3 3/6] rust/kernel/device: return parent at same context 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: <20260510-rust-virtio-v3-3-1427f14d67e1@pitsidianak.is> References: <20260510-rust-virtio-v3-0-1427f14d67e1@pitsidianak.is> In-Reply-To: <20260510-rust-virtio-v3-0-1427f14d67e1@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 , Daniel Almeida , 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=984; i=manos@pitsidianak.is; h=from:subject:message-id; bh=hcTYlDg84gZsUt1opDAEy/hJk/exwjLlY5Z3TwHRPGc=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnFBSXBTY081VG9jamluSWVGRlRXS3R5NUtWaUIzCnZhNmZpSkNXajZiaThzZHYw c1dKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWdDS1VnQUt DUkIzS2Nkd2YzNEowT29FRC85bmZaTCtmVm9DeHpFWVdyZ3Bpc3JxUzN5Q05HTUpKTWZKMXdKMQ pWVi9NZG9rSVppU3pjdXJvZnhZZ1NMNUVRWFgyZDNKTmNDVWh5dzBCdytYNHIybDEwMFRnTm5QV TJyOFVNYVo4CkZoSCtaNFFORTNZVTZXNEZseDlVZWxNYVZMcWJ0dDRJK2p0MlI2TFdTc21xMEVa bGZnSHYyZlVxb3lsTUNsaDQKS0c2Y05Kb21hODNwelVheDVQME1zZXdJY2hKVTRvMCtUbklMcjd HOXg2ejQ4SHczb3U2N3FzSHNWVFF0MXhnawpNbkdDbVh2U3VVc0dxSkdiUngrMmZtVVdXTUNLMn VYMFdZNVhDTmlJeXpBeVlxNXNPQnhNU2pidnhaVnZWKy9kCmhIZzdhQzFSeGVxck5VaStxM1B4L 0hKYVMzWWdud1F1ZG95QncrVDNra29LZHpiRzFMa01PL0JCZE9zMkhlNE0KZmN4ZlZtTlpTNlQ5 TzJDKzFhdjdPMDUzSFIxc2pyZmtPTWFZUVN5M1V3amhBVkRPQmgreEE1VXFLejd2SnlHQwppWWt CU2EwbmJGaGFiTy91TW5GNk5ya0s5eTlFbG0rZDlwcVNMVGxaWTNxUklQZCtMZ24wODc2bHpLaG k4NEhqCkUzMFB0V1k3OFZVMGg0ZDhNMmJhVjhiS0w5bHVXOHM1YnFMRU5UdG96TEo0ZW9HQmU0Y UJQZnJmYTJNOHpKVEsKY0ZVZkd2M1djUEdTNGF4alNXcERoOUkycldZOHlReGhDWUZ5YnNtVER3 QVcyR201dndveWVOdGloNithYWRrRwpyTlRaN01PUXN2dDRRdUNVTVF3NVJzTzE0VDcyU1RhQmJ 2Y0IzRWdodTVQRFNmclk1V29ycVFzbjExVzJreVNaCklqZXNPQT09Cj1PVGlxCi0tLS0tRU5EIF BHUCBNRVNTQUdFLS0tLS0K X-Developer-Key: i=manos@pitsidianak.is; a=openpgp; fpr=7C721DF9DB3CC7182311C0BF68BC211D47B421E1 The return value of `Device::parent` method was defaulting to `Normal` context, instead of having the same context as `self`. Signed-off-by: Manos Pitsidianakis --- rust/kernel/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 94e0548e76871d8b7de309c1f1c7b77bb49738ed..07d2f1225cd87f4fc091a5d6cb6= 26726ae175894 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -341,7 +341,7 @@ pub(crate) fn as_raw(&self) -> *mut bindings::device { =20 /// Returns a reference to the parent device, if any. #[cfg_attr(not(CONFIG_AUXILIARY_BUS), expect(dead_code))] - pub(crate) fn parent(&self) -> Option<&Device> { + pub(crate) fn parent(&self) -> Option<&Device> { // SAFETY: // - By the type invariant `self.as_raw()` is always valid. // - The parent device is only ever set at device creation. --=20 2.47.3 From nobody Sat Jun 13 04:51:51 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 4506D3909B1; Sun, 10 May 2026 13:38:49 +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=1778420348; cv=none; b=PhtkbP7tg/qf0NKdfdSMnA+HPWP8Qpur2eDQjnsdJl3YrEHePpq78REDOmabwr09bYkOEl15Sn8qBvwvebeR4Js1DLmlfza61ILSaVFkuVntwuEGDOxSGH5sVu1gXgXp8Va362d7IRdiup67gJyKK8PyPIBVKg21n06sQGVnktI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778420348; c=relaxed/simple; bh=pzKZ6xIXKmNC75iNGr2a+BGWJ8qX9qSwFR2+WGgrR/8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IE11aCWcx9HjC8sS/jH2TP67j/F4Ra2sZWeZ/V8mjGgdU3+ghjCLO+Hsr0qBl3fh/e2hvjyibpXH5gSo1Cc+fr53KMbJsiKpYRQrMrQ+REOjgE4Okbk+sVOvk7y6452nYL84/eQH9PmwNf6DyIlfGe+AiMfywOZdalf3iidDdTs= 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=nAVGi+EH; 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="nAVGi+EH" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1778420315; bh=pzKZ6xIXKmNC75iNGr2a+BGWJ8qX9qSwFR2+WGgrR/8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=nAVGi+EHJiWZ1Ir2Z8LD3+0DJdXR0E6Gl8dAf6HAsDQThVBIvMhcDBy+6qQ4fmeOh Hx+cam0qyOu+7KSaHdNunJqCRagf3w/O20E4TzrEOwNG9fGaf4afgYMix9caw/Vmaq zaXk2C1wPaWwGroEiK8FDHJYZCynk9T9hBWLAKKsAbSDuzqWf+Ebi5rzjC49ObCq4O 6ju75C51+T+MgGhbpEs6Cx9NUhr/XkvwlSAclbHDUBNH0r26LjloNdV1IH6CSaY2Bk ri55KD8E1CmnNiwWnhWi4wbcGO/IhyKcpkIWaCu4D2UFz8xpMIpqprfAe8IpdcAj1A UdB4SxUqC7CCrELdwr7b72qYtDjRt3SMpo5K/GuBQ1ojEarN6VHgLsmJZnVuQjLuD3 0MWJXx3NOWr2sn3QzeGVaRylFBxc+2QI+yjOReuSFoTNutdHxJGMMf2/qc/EqOlZUV JXV75zDs6canffMviWDd4Mzol8+GX/esQgP3njZo9dO2F1Nbm1DwyyNCHNmXhH7EQM R2DqdcIO8SdPhx9NnjJb1Glwn3vYc1TGaAndCrdUti0fZfXGt71lq3OR5W1DD2QREZ /pGf5sagEiFMK1aANtT2V042LBWT937cfUrSYiSDQpFjSw3lUuiJCyeNXys/lBr5nw SIU06/FZaNwxR2SQCAkBcHSQ= From: Manos Pitsidianakis Date: Sun, 10 May 2026 16:38:17 +0300 Subject: [PATCH RFC v3 4/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: <20260510-rust-virtio-v3-4-1427f14d67e1@pitsidianak.is> References: <20260510-rust-virtio-v3-0-1427f14d67e1@pitsidianak.is> In-Reply-To: <20260510-rust-virtio-v3-0-1427f14d67e1@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 , Daniel Almeida , 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=30065; i=manos@pitsidianak.is; h=from:subject:message-id; bh=pzKZ6xIXKmNC75iNGr2a+BGWJ8qX9qSwFR2+WGgrR/8=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnFBSXBUMVdUNzVtcktuU3VIVE92Vm1Jb3cyZTBqCkE3QVZpLzdvNEl5WjkvSmhw eWFKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWdDS1V3QUt DUkIzS2Nkd2YzNEowRzlyRC85Ull1em9mNkpMY0RGSFpEMFZqb21ySFg2VVNlNHZLSDNyYWZZRg o3VGZnUXFkWGR1MTgzeENDbFZLSHNnTHZZM01GL1ZQNFZsdWpVYlBCd2dLU1duQndyUnBqdFNMU E9ybFJSdHcrCko2TDhkb1QrdTBMU0pDRk9SaTdaTFJWTnV4Rm9VTlNEbDhwVDM3ektGK0VDdmow RllHcUV4Ry9pNC9qcDZ6VEoKU0VyS0NJdHl1Q0lkSHAybjV4SHIrZFhDc3BUcUVCV3ZqYVV5QU5 BSHBqVWQ0K1FKeEFJUDV5MUNoaW81L1hZcQpmUVprdGZmWmpGM0dSOU9SeHQ3NXB0QUFSV21La2 JObzlkeDJkRE5oMWZzRm5hTy9OVDZjSE4xUzZScmJRVGhSClM5UTFGQWV0SVdGNXFOQ1AzRG1sc WZKMXhJNTRCV043dURWcWNLZkNjRStoRzN2eEoyR1pVMCtVSzhGZDRSVDEKRmoxRGNwU0VkUjdt SEcrWGhJWDAyUXpZK2Q5OGtwSDArY2drUTVXclhkbjRyaXdlRVhFR1FnUnphZjdlOGRHYgpjbzQ 2RGw5WitMWFluRkNnVzF5b0RkZU9kNEx2dWFLbkNBR0lSMnJWaGxxbSsrTklxTDJ6bXowQXBjZU dlMmNDCk5OZkZ4a28xQmJRc1VuaXNFMXlJWHprQ08zWFE3S2hKRS9jd0FnaFNYREd4YU1ER24yb 2duN3hSUVZHS01yTmIKUU1QeDVKS2Q4azJibk1BaWJoZE1xT1VaMytIWFkwbnhHaFNGaWlKR0JF OFlYUXBxbm5IUTFOZW9tMmZyNTg3WgpMcXc1cllEbFgvMEtlZS9DWXVzajU0SjdNSUh4ODdadTJ RTEpRL2w2YUFUckFNTy9RZ0x3NXdkQUY5bVdsVXF1CnBjUXRKdz09Cj05Y0UyCi0tLS0tRU5EIF 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/virtio.rs | 423 ++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/virtio/utils.rs | 57 ++++++ rust/kernel/virtio/virtqueue.rs | 314 +++++++++++++++++++++++++++++ 5 files changed, 798 insertions(+) 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..061394f441dfa27f99939b5c416= 0e4161a7eaa1e 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 =3D "y")] +pub mod virtio; pub mod workqueue; pub mod xarray; =20 diff --git a/rust/kernel/virtio.rs b/rust/kernel/virtio.rs new file mode 100644 index 0000000000000000000000000000000000000000..a5a4e2cfec55bc7cbca0d42b198= fde6cd2b25f1c --- /dev/null +++ b/rust/kernel/virtio.rs @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! VIRTIO abstraction. +//! +//! To implement a VIRTIO driver: +//! +//! - Implement the [`Driver`] trait for your driver type (use [`virtio_de= vice_table`] macro to +//! declare the `ID_TABLE` associated item) +//! - Use the [`module_virtio_driver`] macro to declare your module + +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, + ptr::NonNull, // +}; + +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) + } + + #[inline] + /// Create a new device id with vendor + pub const fn new_with_vendor(device: VirtioID, vendor: u32) -> Self { + // Replace with `bindings::virtio_device_id::default()` once stabi= lized 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 should try not sleep si= nce 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>) { + _ =3D (dev, this); + } +} + +/// 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")] + #[inline] + 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")] + #[inline] + 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()) }; + let mut inner =3D KVec::with_capacity(vqs.len(), GFP_KERNEL)?; + for vq in vqs { + inner.push(NonNull::new(vq).ok_or(EINVAL)?, GFP_KERNEL)?; + } + Ok(virtqueue::Virtqueues { inner }) + } + + /// Delete virtqueues from this device. + pub(crate) 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. + #[inline] + 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) } + } +} + +impl AsRef> = for Device { + #[inline] + 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) } + } +} + +/// 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::() }; + dev.ready(); + if let Err(err) =3D T::init(&data, dev) { + // SAFETY: `Device::set_drvdata()` was just called so it's= safe to re-obtain the + // data. + let data =3D unsafe { dev.as_ref().drvdata_obtain::() }= .unwrap(); + T::remove(dev, data.as_ref()); + drop(data); + return Err(err); + } + 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); + dev.reset(); + } +} + +/// 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..8dca373f10a6906b891a9420c13= cd8e9e929c412 --- /dev/null +++ b/rust/kernel/virtio/utils.rs @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Helper types and utilities + +macro_rules! endian_type { + ($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!(u16, Be16, to_be, from_be); +endian_type!(u32, Be32, to_be, from_be); +endian_type!(u64, Be64, to_be, from_be); diff --git a/rust/kernel/virtio/virtqueue.rs b/rust/kernel/virtio/virtqueue= .rs new file mode 100644 index 0000000000000000000000000000000000000000..781326c1723eb67a8c62524795b= a431141fea202 --- /dev/null +++ b/rust/kernel/virtio/virtqueue.rs @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Virtqueue functionality. +//! +//! # Discovering virtqueues +//! +//! Inside your driver's [`kernel::virtio::Driver::probe`] method, call +//! [`kernel::virtio::Device::find_vqs`] method with your [`VirtqueueInfo`= ] struct. +//! +//! # Passing data to virtqueues +//! +//! Create your data as owned [`SGTable`] with: +//! +//! - [`Virtqueue::new_readable_sgtable`] for data that can be read from t= he device, and +//! - [`Virtqueue::new_writable_sgtable`] for data that can be written fro= m the device +//! +//! These methods will make sure to create the scatter-gather tables and D= MA map them to the +//! appropriate VIRTIO transport. +//! +//! To add the tables to the virtqueue, call [`Virtqueue::add_sgs`]. + +use crate::{ + alloc::{ + allocator::VmallocPageIter, + Flags, // + }, + bindings, + device::Bound, + dma::DataDirection, + error::{ + code::{ + EINVAL, + ENOENT, // + }, + to_result, + Error, + Result, // + }, + page::AsPageIter, + prelude::*, + scatterlist::{ + Owned, + SGTable, // + }, + str::{ + self, + CStr, // + }, + types::Opaque, + virtio::Device, // +}; + +use core::{ + 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 { + #[inline] + /// Create a new [`VirtqueueInfo`] + pub const fn new( + name: &'static CStr, + ctx: bool, + callback: Option, + ) -> Self { + Self(Opaque::new(bindings::virtqueue_info { + name: str::as_char_ptr_in_const_context(name), + ctx, + callback, + })) + } +} + +/// A container for discovered virtqueues returned by [`Device::find_vqs`]= method. +/// +/// This type dereferences to a `NonNull` slice. +/// +/// It deletes the virtqueues when dropped. +pub struct Virtqueues { + pub(crate) inner: KVec>, +} + +impl Drop for Virtqueues { + fn drop(&mut self) { + let inner =3D core::mem::take(&mut self.inner); + let Some(first) =3D inner.into_iter().next() else { + return; + }; + let first_ref =3D unsafe { first.as_ref() }; + let Ok(vdev) =3D first_ref.dev() else { + return; + }; + vdev.del_vqs(); + } +} + +impl core::ops::Deref for Virtqueues { + type Target =3D [NonNull]; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +/// 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. + #[inline] + pub fn dev(&self) -> Result<&Device> { + // SAFETY: By the type invariants, `self.as_raw()` is a valid poin= ter to a `struct + // virtqueue`. + if unsafe { (*self.as_raw()).vdev }.is_null() { + return Err(ENOENT); + } + // SAFETY: the pointer has been promised to be valid when self was= created + Ok(unsafe { &*(&*self.as_raw()).vdev.cast::>() }) + } + + /// Get the vring size. + #[inline] + #[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. + #[inline] + #[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. + #[inline] + #[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. + #[inline] + #[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. + #[inline] + #[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. + #[inline] + #[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. + /// + /// This method returns a pointer to the `token` value passed in [`Vir= tqueue::add_sgs`] method + /// and the amount of bytes that were written by the device. + #[inline] + #[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)) + } + + /// Add a list of scatter-gather lists to virtqueue. + #[inline] + #[doc(alias =3D "virtqueue_add_sgs")] + pub fn add_sgs<'token, PIn, POut, Token>( + &'_ self, + out_sgs: &'token SGTableReadable, + in_sgs: &'token SGTableWritable, + token: Pin<&'token Token>, + gfp: Flags, + ) -> Result + where + for<'a> PIn: AsPageIter =3D VmallocPageIter<'a>> + 'stati= c, + for<'a> POut: AsPageIter =3D VmallocPageIter<'a>> + 'stat= ic, + { + let out_sgs_num =3D u32::try_from(out_sgs.inner.iter().count())?; + let in_sgs_num =3D u32::try_from(in_sgs.inner.iter().count())?; + + let Some(total_size) =3D out_sgs_num.checked_add(in_sgs_num) else { + return Err(EINVAL); + }; + + let mut sgs =3D KVec::with_capacity(2, GFP_KERNEL)?; + + for entry in out_sgs.inner.iter() { + sgs.push(entry, GFP_KERNEL)?; + } + for entry in in_sgs.inner.iter() { + sgs.push(entry, GFP_KERNEL)?; + } + + if usize::try_from(total_size) !=3D Ok(sgs.len()) { + return Err(EINVAL); + } + // SAFETY: `self` has been promised to be valid when self was crea= ted + to_result(unsafe { + bindings::virtqueue_add_sgs( + self.as_raw(), + sgs.as_ptr().cast_mut().cast(), + out_sgs_num, + in_sgs_num, + NonNull::new(core::ptr::from_ref::(&*token.as_ref()= ).cast_mut()) + .unwrap() + .as_ptr() + .cast(), + gfp.as_raw(), + ) + }) + } + + /// Create a scatter-gather table readable by the device. + pub fn new_readable_sgtable

( + &self, + pages: P, + flags: Flags, + ) -> impl PinInit, Error> + '_ + where + for<'a> P: AsPageIter =3D VmallocPageIter<'a>> + 'static, + { + pin_init!(SGTableReadable { + inner <- SGTable::new( + self.dev().unwrap().as_ref().parent().unwrap(), + pages, + DataDirection::ToDevice, + flags, + ), + }? Error) + } + + /// Create a scatter-gather table writable by the device. + pub fn new_writable_sgtable

( + &self, + pages: P, + flags: Flags, + ) -> impl PinInit, Error> + '_ + where + for<'a> P: AsPageIter =3D VmallocPageIter<'a>> + 'static, + { + pin_init!(SGTableWritable { + inner <- SGTable::new( + self.dev().unwrap().as_ref().parent().unwrap(), + pages, + DataDirection::FromDevice, + flags, + ), + }? Error) + } +} + +/// An [`SGTable>`] that is guaranteed to have been DMA-mapped as= device-readable. +/// +/// Created by [`Virtqueue::new_readable_sgtable`]. +#[pin_data] +pub struct SGTableReadable

{ + #[pin] + inner: SGTable>, +} + +/// An [`SGTable>`] that is guaranteed to have been DMA-mapped as= device-writable. +/// +/// Created by [`Virtqueue::new_writable_sgtable`]. +#[pin_data] +pub struct SGTableWritable

{ + #[pin] + inner: SGTable>, +} --=20 2.47.3 From nobody Sat Jun 13 04:51:51 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 BF09638F65C; Sun, 10 May 2026 13:38:45 +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=1778420329; cv=none; b=nHuZ2ap2FujcNS1/A223DR1JaTv9Ilt02kD2TQPAIn3bmdDe0qEjd7q0XvZmeJGozQfKA91iJJDQHzwYx+aqsUx4U+9tJOfuy7WS++cHionRyOUC/lafIxk/Y0ODj6dGQGl7QbmOH9oRYblUHWUL2i3HkVEHAfJ7MKyk/+tnA2Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778420329; c=relaxed/simple; bh=msIA3QDkNRl5CiYMJuFdB8gcwSF6bQ5gs2Bh4tXdmNA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=vBjcKNUyV/SE3k15hECPcFXw0Gxn71v8VwNAG3RkqNfy1tzZote/iNkkj5EglWqnaWV++BO3vS3advX/Y3i2DVK43OnuArEtaq0zkLW7cUR1wIZ58OBhxySJqLHniH1y2uYQZzbKGozfSavrzqDbwoqMOihVxMq1FOazN6Bagrs= 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=gLj+oYy4; 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="gLj+oYy4" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1778420316; bh=msIA3QDkNRl5CiYMJuFdB8gcwSF6bQ5gs2Bh4tXdmNA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=gLj+oYy4O5i+m33NxYSFhA0eIGBoRBt6XpUYtMiRzEgkFRWNfC88dvUzvdchjg5Os bYjT409u+zjnVrAmVm4AKXhKTmpTrbzB+nXZmFq8oi8YH8eM1qPEXGlkIP28AhxT/m pBF7DCnnmod51igXs0MFZDtS/EqbTVhbNCqs8Ex1fAi5LMGQEw2IEkVuzexA7fxtU2 lULwiWSZNT/OlqzbCbLq5bcEkeotQ+jlxKpm86N4yhCwasL8vapgyexvyu4tWAn/go mZyQZRfUeAjDDgqA0fEgOaL9joCKjehzk/AGWeWJ7fu6jjzYklcf7QYzv8oYnGNtc8 lgG+qugDTdEpgLEbb/bc1UBMesirur4yQByjGd7CpONu+Q0TuSZ4N5QLGagTFUvLbp OkwC3CcBuQYUCXJMX53um51f6dPJ8z3KLyfVUOoOgd6l0acyJEzgbfpiQIHG5lKa2O bq6ghgmPgRJUv9JHPxJ0Gr5+2MkPHKyeUnsqCS4Ac88lD5IshamK6Pg2P3mEXyBNXn 0G1KGd1rguQ3QCYFdZA5+T8dFzsZvfg6fvcn0/LLwwGJvIqpl59RrRfPB92XkNFthe +nUA4kKoEsth/gz+o0fc7CFCWy7lsDdu4sDVAkIlGDzEYTaoCXWHsBvmqI0U6aJIVX EoutaNAKlpozT6GCaMzXg4gA= From: Manos Pitsidianakis Date: Sun, 10 May 2026 16:38:18 +0300 Subject: [PATCH RFC v3 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: <20260510-rust-virtio-v3-5-1427f14d67e1@pitsidianak.is> References: <20260510-rust-virtio-v3-0-1427f14d67e1@pitsidianak.is> In-Reply-To: <20260510-rust-virtio-v3-0-1427f14d67e1@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 , Daniel Almeida , 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=2340; i=manos@pitsidianak.is; h=from:subject:message-id; bh=msIA3QDkNRl5CiYMJuFdB8gcwSF6bQ5gs2Bh4tXdmNA=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnFBSXBUanRweDRET2FzWmJPa1dkRDAydU42eEpVCk1wMFFVV3RVWHNrWHdXZWhz QldKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWdDS1V3QUt DUkIzS2Nkd2YzNEowRWVORC85UXdiOFJuU2J1Zi93dkhDekJ3L1J4cWdicGg5SjBZUURRR0lHNg pQazJGTnhXTVE0K1JVVTY4NURFM2ViTUdnbUxBL1NSUWFEL0ZkNkJrQzJTcll3dHl3NkVJYnNyV Wp2eWVzWHZVCnp0Zk53WWl3ZEgwZTVORjJQR1VaaXdDZkx2eFdFYTMxZk55SENyMTgzR2h0RHBU NU9mRUN5UXUxRXZpN2RkZlUKS0d0V2hweGhSYldMSGdkR2IvRncvNTErY1NEOWpzb29SYzVaQkc 0cTlsWktFeWRBWXdsSHk3bWxUZUNORisyKwo1bjZHWXdYR0tUNjZoTkd6ZGl5N090MnBPVFZvbD lDODVYUnBKTUd4Y1ZWT3dmR04rbVdrOVNZSnJQRWx6VTdJCkh3WTg0d05UWmFoMzl6RGNYRDNVR DFEVEp2dmhTL0V6ZFFlSlNOb1pqbWFuTmp4NjlLL0NDeTE2NDB4enBUOGEKZWVNZ1FzU3VFRlRK dHRDNzFZbEIrak83bkd1Y1ZRbkdzWXVtalp3eXQyckVlUlR2Z3JiRHRMTWs2clJzeDkreAptM1d KUlRiY3FmQlBSWlkwb01Uei9mcVl2NDJrS2lRcjBvMlNQbUd6MmpNeDlZNi9IK3VoV01LMVNpdy tjMnU4CklCeW51WDZKYlZBbkdWOXFGM2czc0NYYW94N2F4MGRpVHRUS3FEMnVVNUN0a0JvcFdwQ 1RlVUtGanpINHU0dVIKQ3VjQThkazVqYklhckRnYStTM1orbXZaL2piMjdWY2VPTEFRVVZKVGRs SG9UTnpDdE9SMmdlNHk4eGplaEgyTQpLdUdJZjZWUTlFWFJ0QzVVcUdBdVRwb2RkUXdXemtCajJ DMTB1ZE9EQkg4MkUvTndFYWp3bjFWcyt3dks1Wk96ClVnN2dTQT09Cj1MemZGCi0tLS0tRU5EIF 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 | 42 ++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/rust/kernel/sync/completion.rs b/rust/kernel/sync/completion.rs index c50012a940a3c7a3e0edf302c8f833bdc4415200..17c9e48a5359c0c885be9ebf684= 3e74d5abe56e5 100644 --- a/rust/kernel/sync/completion.rs +++ b/rust/kernel/sync/completion.rs @@ -6,7 +6,12 @@ //! //! C header: [`include/linux/completion.h`](srctree/include/linux/complet= ion.h) =20 -use crate::{bindings, prelude::*, types::Opaque}; +use crate::{ + bindings, + prelude::*, + time::Jiffies, + types::Opaque, // +}; =20 /// Synchronization primitive to signal when a certain task has been compl= eted. /// @@ -109,4 +114,39 @@ 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 an interruptible task without a timeout. + /// + /// See also [`Completion::complete_all`]. + #[inline] + 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 an interruptible task with a timeout. + /// + /// See also [`Completion::complete_all`]. + #[inline] + pub fn wait_for_completion_interruptible_timeout( + &self, + timeout_jiffies: Jiffies, + ) -> 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 { + return Err(ETIMEDOUT); + } + match Jiffies::try_from(ret) { + Ok(ret) =3D> Ok(ret), + Err(_) =3D> Err(Error::from_errno(ret as c_int)), + } + } } --=20 2.47.3 From nobody Sat Jun 13 04:51:51 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 E651838F25A; Sun, 10 May 2026 13:38:44 +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=1778420334; cv=none; b=UxSdTs8EcXn/JeS6wNV+SjzD7xeR76eYdukvRD8raHJ8NfaoQn/ywMZNIjJSrS4fJnEej+cntWNkInGoJUFu0euPm11KabnWDEqq5B+u4lUFC2zXyVv9RpFx3Wr+RSx6Y4CGkmvYMzAi6vo2ec3RhW2JQaI7s3ctJ+sGWytvcpc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778420334; c=relaxed/simple; bh=izTjslYQ1hggeS4KUt9UbBQEx214atZEccKQMZepSbI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=iz/5oNAivTtAxWIwA/m/gi2wsQv2xMhlQJodZreJ7F7WOvO2RYwcQNOfltZRH61CYWxtjkWDhurCfkARYnAjydB3d15AwO0uRB06VZDaId/g2xWrPH/ra9w66faF7SVFH+Zdr9I54Whh+FysEDyBeaH6r2R2UZXCzx82hXCamF0= 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=G59d1N99; 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="G59d1N99" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1778420317; bh=izTjslYQ1hggeS4KUt9UbBQEx214atZEccKQMZepSbI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=G59d1N99Ntymc366RcCFcGbR1AgrEB+gDbWlHeEP5lu9Ch02oQiMruehowPJ96M/H kYUauCiMnmserbt9/XbgYK+qWJgQWkQJxk0W+EJkgsFwHke2Kv039Qi9N3tNeqHP49 yje+NQLnwo07OXXQ9JZGDc758pvGAmxCmRtKuCLMIM0M4qiD7ud/xHhA32+xz2Nj47 epZE2C6sd80NSeaOTJdJrXl34BYyjpiBLemUxQEGgTY2hdggf3I9m6M/9YtggdW11J RC6bSl5sLOm8OWGx4/UGwkd/S3Ghdqupy1ymjHy6kv4S78IcA4DznZyKsMo7Fl+Kqz asS7d64klRDoWoG16DPflH940uSseoaPC+a0m8MaXUutissLnoGu3V5MSxVq7OCjM9 y8EXsnryeF/N0CrI6U0U0u702U6Z3glfVjBvYz/0QTut0wPeIsiK3STZ8UTxPdSF0N /Ov/Q0ufbMyVoBfu+l2QGUkLHuF0srv0EjXBlTu3DUddk5/X1fuaW8fj8dp3EjBLdp 7FNliig9D2Wpt7r6zP2LWhWSMdIezdNxPtJxXuvo5jNEV1RYPKDP6c8tY73R5GhXUJ esVV7adMWiPcytpcIi1UsFaRZPHOjgfxiN92+aJa+NSGOfgog21zNGXwEUf+E81jYO n+3ZVIF8QiIr+7p2FvjwNXU4= From: Manos Pitsidianakis Date: Sun, 10 May 2026 16:38:19 +0300 Subject: [PATCH RFC v3 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: <20260510-rust-virtio-v3-6-1427f14d67e1@pitsidianak.is> References: <20260510-rust-virtio-v3-0-1427f14d67e1@pitsidianak.is> In-Reply-To: <20260510-rust-virtio-v3-0-1427f14d67e1@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 , Daniel Almeida , 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=15020; i=manos@pitsidianak.is; h=from:subject:message-id; bh=izTjslYQ1hggeS4KUt9UbBQEx214atZEccKQMZepSbI=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnFBSXBUSS9QN29xUEJVeDV0UWFTbzYvYSt2dWVLCkw5NCtOMkR0RUxuUm9rQ0g2 eVNKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWdDS1V3QUt DUkIzS2Nkd2YzNEowRE83RC80MnhvMGZKbkYrSnhiUE5BSDZGNER1L2hFTUlqQUtqdGlGYXlWcA pnRjQ5ek5HOUhBcmF2ZlE0YjVlNXhMY3hsNlFMYzVzdmNhVzh0T0MxV3JhVXB0T1ArTmprc0JWR VMrUnUvWDhZCmZYc2dNbklxSHVkSGlab0txREJGaitQV0tIQnNNNFFqdjlkZ3dsUTBKTnV0TjAx VEtBcE4wOEZkVmtpRXkybTUKa2hLLzZTU2M2SHVFTkxkUXFQRTVGUWVQdXhWK2V5NHE4VW5haHp OcFArUnNHRFlGaW9XRUxQbGl2Umd1NmU4RgpYcndUM3c2WURtZ2V0RFM0UXlENHlxTmRnb1NwWk pDczhEREhLU3c5amMzeUxReHdDRFVkdUhkeDdVbG84b1NHCkhPK0grOFdZbyszbXAza0JBZW9Za 0dDcldUWjFvbXFnZWxPc09kY0RxZHROZEkvOEtzVGU5NUtMc2JMUlVTcW0KeXdXekpEYmVkKzNj dUZrWkV1aEhjVWRzbTA3ak9pY2lTSTg1SER6Q2luMVcwaytpNXdyd0R4SWp6aWhzK2YrQgpsL2l JQTVJcmZPbVpxWTdLMElnakZqNUFqeHVxM0h2dTAwdmQ5NXFzZmZ6V2ZpOS80SzBNMzcrTTNMNk VRUFRpClVNVXQzdU1kaUJlMEdwRnVITE1idnJNR2xIZjNHQUQxdy93Ty9Gc0ZoQXdacGxkMzRCY 243NjcyNHFkc0djd1AKU0pPTUhZajFaS0JnakVsdUNVM202WDhuYXNiT3FUUlcvR1JaQWhaNnZ6 ZFUvZi9IT2lLWTV0MS9KYU1BNmloMQpQOVkyeVUwd091OERnNGtuaS9KZjdzbHNZSmlLTWg0aVN 2TFdaVjZodUE5MzFzMFRCMmJlUHlkQk1SaTZHTGJlCm03M3FIdz09Cj1Ic1k3Ci0tLS0tRU5EIF 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 | 403 ++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 420 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..81f8b377f6c92716c17ea11542f= b4262cfd90e1c --- /dev/null +++ b/samples/rust/rust_virtio_rtc.rs @@ -0,0 +1,403 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust virtio driver sample. + +use core::{ + ptr::NonNull, // + sync::atomic::{ + AtomicU16, + Ordering, // + }, +}; + +use kernel::{ + device::{ + Bound, + Core, // + }, + new_mutex, // + new_spinlock, // + prelude::*, + sync::{ + Completion, + Mutex, + SpinLock, // + }, + virtio::{ + self, + utils::*, + virtqueue::*, // + }, +}; + +use pin_init::{ + stack_pin_init, + stack_try_pin_init, // +}; + +#[pin_data] +struct Token { + resp_actual_size: u32, + #[pin] + responded: Completion, +} + +#[derive(Copy, Clone, Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_req_head")] +struct ReqHead { + msg_type: Le16, + reserved: [u8; 6], +} + +#[derive(Copy, Clone, Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_resp_head")] +struct RespHead { + status: u8, + reserved: [u8; 7], +} + +#[derive(Copy, Clone, Debug, Zeroable)] +#[repr(C)] +#[doc(alias =3D "virtio_rtc_resp_cfg")] +struct RespCfg { + head: RespHead, + /** # 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: RespHead, + 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: RespHead, + 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, +} + +/// Send a message and receive reply +fn send( + req_data: Request, + vq: &SpinLock, + timeout_jiffies: c_ulong, +) -> Result { + // FIXME: This lock should also disable irqs. + let guard =3D vq.lock(); + + let req =3D VBox::::new(req_data, GFP_KERNEL)?; + let mut resp =3D VBox::::new_uninit(GFP_KERNEL)?; + let resp_ptr =3D NonNull::new(resp.as_mut_ptr()).unwrap(); + + stack_pin_init!(let token =3D pin_init!(Token { + resp_actual_size: 0, + responded <- Completion::new(), + })); + stack_try_pin_init!(let req_sgs =3D guard.reqvq().new_readable_sgtable= (req, GFP_KERNEL)); + let req_sgs: Pin<&mut _> =3D req_sgs?; + stack_try_pin_init!(let resp_sgs =3D guard.reqvq().new_writable_sgtabl= e(resp, GFP_KERNEL)); + let resp_sgs: Pin<&mut _> =3D resp_sgs?; + + guard + .reqvq() + .add_sgs(&req_sgs, &resp_sgs, token.as_ref(), GFP_ATOMIC)?; + + if guard.reqvq().kick_prepare() { + guard.reqvq().notify(); + } + drop(guard); + + if timeout_jiffies > 0 { + token + .responded + .wait_for_completion_interruptible_timeout(timeout_jiffies)?; + } else { + token.responded.wait_for_completion_interruptible()?; + } + + if token.resp_actual_size as usize >=3D core::mem::size_of::= () { + // SAFETY: all response types contain a `RespHead` header at the s= tart. + let head: &RespHead =3D unsafe { resp_ptr.cast().as_ref() }; + match head.status { + 0 =3D> { + // OK, do nothing. + } + 1 =3D> return Err(ENOTSUPP), + 2 =3D> return Err(ENODEV), + 3 =3D> return Err(EINVAL), + 4 | 5_u8..=3Du8::MAX =3D> return Err(EIO), + } + } else if token.resp_actual_size as usize !=3D core::mem::size_of::() { + return Err(EINVAL); + } + // SAFETY: we have checked that the device wrote the correct amount of= bytes for this type and + // has returned a successful status code. + let resp =3D unsafe { *resp_ptr.as_ref() }; + + Ok(resp) +} + +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 { + inner: Virtqueues, +} + +// SAFETY: `VirtioRtcVq` is safe to be send to any task. +unsafe impl Send for VirtioRtcVq {} + +impl VirtioRtcVq { + fn new(inner: Virtqueues) -> impl PinInit> { + new_spinlock!(Self { inner }) + } + + fn reqvq(&self) -> &Virtqueue { + unsafe { self.inner[0].as_ref() } + } +} + +#[pin_data(PinnedDrop)] +struct VirtioRtcDriver { + #[pin] + virtqueues: SpinLock, + num_clocks: AtomicU16, + #[pin] + registered_clocks: Mutex>, +} + +#[pinned_drop] +impl PinnedDrop for VirtioRtcDriver { + fn drop(self: Pin<&mut Self>) { + pr_info!("Remove Rust virtio driver sample.\n"); + } +} + +extern "C" fn vq_requestq_callback(vq: *mut kernel::bindings::virtqueue) { + // SAFETY: The kernel called this virtqueue callback and it must have = provided a valid `vq` + // pointer + let vq =3D unsafe { Virtqueue::from_raw(vq) }; + let dev: &virtio::Device =3D vq.dev().expect("Could not get dev= ice"); + let data =3D dev + .as_ref() + .drvdata::() + .expect("Could not borrow drvdata"); + 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], + }; + let response: RespCfg =3D send(head, &self.virtqueues, 0)?; + pr_info!("Got response! {response:?}\n"); + + Ok(response.num_clocks.into()) + } + + fn process_requestq(&self) { + let mut cb_enabled =3D true; + loop { + // FIXME: This lock should also disable irqs. + let guard =3D self.virtqueues.lock(); + if cb_enabled { + guard.reqvq().disable_cb(); + cb_enabled =3D false; + } + if let Some((token, len)) =3D guard.reqvq().get_buf() { + drop(guard); + pr_info!("process_requestq got buf {len} bytes\n"); + let mut token =3D token.cast::(); + // SAFETY: pointer points to a valid Token that we have ad= ded to the virtqueue. + let token_ref =3D unsafe { token.as_mut() }; + token_ref.resp_actual_size =3D len; + token_ref.responded.complete_all(); + pr_info!("process_requestq ok\n"); + } else { + if guard.reqvq().enable_cb() { + return; + } + cb_enabled =3D true; + } + } + } + + fn clock_cap(&self, clock_id: u16) -> Result { + 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], + }; + let response: RespClockCap =3D send(req, &self.virtqueues, 0)?; + pr_info!("Got response: {response:?}\n"); + Ok(response) + } + + fn read(&self, clock_id: u16) -> Result { + let req =3D ReqRead { + head: ReqHead { + msg_type: VIRTIO_RTC_REQ_READ.into(), + reserved: [0; 6], + }, + clock_id: clock_id.into(), + reserved: [0; 6], + }; + let response: RespRead =3D send(req, &self.virtqueues, 0)?; + pr_info!("Got response: {response:?}\n"); + 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 { + let vqs_info: [VirtqueueInfo; 1] =3D [ + VirtqueueInfo::new(c"requestq", false, Some(vq_requestq_callba= ck)), + //VirtqueueInfo::new(c"alarmq", false, vq_callback), + ]; + try_pin_init!(Self { + num_clocks: AtomicU16::new(0), + virtqueues <- { + 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); + } + }; + + VirtioRtcVq::new(vqs) + }, + registered_clocks <- new_mutex!(KVec::with_capacity(0, GFP_KER= NEL)?), + }) + } + + fn init(&self, vdev: &virtio::Device) -> Result { + let num_clocks =3D self.req_cfg()?; + self.num_clocks.store(num_clocks, Ordering::SeqCst); + for i in 0..num_clocks { + 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(_: &virtio::Device, _this: Pin<&Self>) { + pr_info!("Removing Rust virtio driver sample.\n"); + } +} + +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