From nobody Mon Jun 8 11:05:06 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 A08863D1A97; Fri, 29 May 2026 15:50: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=1780069852; cv=none; b=PeEQJeMs4ALPf/k7GSZnSF9I4wp2l9t7xG8iYSTr+sI+7s/WdmxF8YZ8KpJFRAos7DlSG4/Vy50sZiZRglToxQg43p/p8ijWxV0qcaJGUVSvgfqpoSxWZQUDh4auD78bsTjqSPcTGsDjNFKbjopbqCCUV3QwbsKCpSv4NkM8Kz8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780069852; c=relaxed/simple; bh=SjcJryr33uIhZxUinLbLFv9BZ+5skmOnZPbvt/KLvHg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=X0BqSqBcN50+QrH520Hry/M3LhNQ6L9E7LSiTAXqwd8ON13zzMantt8dZgT76Pi/Qn+/EGIapsuAJElNw/AXgKmwfc+YD5OYG/WWuaiiIz1E+F/dBJjCMoix/VPi0UPl53nEdO5rc/UBV1e3aH9iZhIMSgUanoZJvM7jOcmEANw= 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=VDZ+Mibz; 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="VDZ+Mibz" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1780069841; bh=SjcJryr33uIhZxUinLbLFv9BZ+5skmOnZPbvt/KLvHg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=VDZ+MibzE28FkttrrfLf6qavJB4TW8ix3yZIq0B77mG0lk8pjdpelLuCxXy8mWmAt rvNhcKXDBQ8zFClGf17fqwKZzwN9E2EDIhXHaD6FDvo40q55TpC1IYeRQuoat2UXwa u4WpT81SqppABYiHc5Px/GykUj/i3oCXiMUHVGGSF66D5q+AbKyw05aKyi2RmLz7ZQ CCn3TqtUcwT8lyKjpGHJgycAdMCEtk/ywGw2tSC36b1Lm/TFQU4fNUpQ1KbIhoGKey CNe/FLIftHDJ5BaItmgUTVYf80i4B+aa58UzQ0UUI1gZg8sP7KbM+yx3p8dXeOkGD/ xZ0aA0dx1dYB0o/EDtphJcumlaHq4ANWDQDwfiqyrctbpZfe8vGYix7v2yTuB6BYKf o5S9aqGiLDqjE6FEj3h8vtAcg+eR6QwGwIum2sW6KLBhhloR+5DvNCFCHmWcHiupSw KAnw8QTT5DKzmF0JmjjNxsk4fRnc8M6t7oHMKywGq1nK8PyoLCvAJgOG88jg0LL9fP cZpVDrp06cxz98dIvUOaj66CYx7V/Y0Z0Lp42n5oz9wQySUEW+Lh54JB/6oV/Kv54c Wf7fVodG41epV/EdNsYVZ9qgMDOJfKgqEopMWEqirybn+/OdwTuGUdwoemouyF1/Lw glhYraFQ73vx+0rgAZ8kDobE= From: Manos Pitsidianakis Date: Fri, 29 May 2026 18:50:26 +0300 Subject: [PATCH 1/2] rust/bindings: add hw_random.h 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: <20260529-rust-hw_random-virtio-rng-v1-1-b3153dd90311@pitsidianak.is> References: <20260529-rust-hw_random-virtio-rng-v1-0-b3153dd90311@pitsidianak.is> In-Reply-To: <20260529-rust-hw_random-virtio-rng-v1-0-b3153dd90311@pitsidianak.is> To: Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Herbert Xu Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-crypto@vger.kernel.org, manos.pitsidianakis@linaro.org X-Developer-Signature: v=1; a=openpgp-sha256; l=679; i=manos@pitsidianak.is; h=from:subject:message-id; bh=SjcJryr33uIhZxUinLbLFv9BZ+5skmOnZPbvt/KLvHg=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnFHYlhNMVJnMU0wMjM5cWcxTjNYVi9nR3BqcnNzCkdKcFNJR1B6bDY2YXlmQmZH bktKQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWhtMXpBQUt DUkIzS2Nkd2YzNEowTWxkRC85ZzJ2RkFhUUM4WSs1b2tJVDY3ZHBwUWg4bUVhVGp3Sll4VXczUw pyMkJjT0R1Nk9BbWVTdGFnYVFnYU9HQyt1NXMzMnl6eWxHcjlWUWNrZXJOSkVEOWZISlZTL3RRO UFtUURYZ1RaCmhsN2xWQzFZZit3aE5JNHlldksrUWtpMkplK3lBUkZDREdGUU1YV2FFOHp6dHkw RUZuK0R5NEhYVzBNZXA3ZGIKZXVOVXBpR3FHNWR5bGZnTVpoM3NySG5nVUZVblpHVEpnZUFjam5 5dHZRcHJzRmJPTEUwT1BvSlF6WElTcVFBcApEV0p4cnhtMk5FLzVKN1RXVVdwK3NZN3VIOWx0bX NKUmxlbG5PMjlWWFlaL2c5MTZ4cm9TQkRLdnV5UzVpanRsCmh4aGR1VUNwNFJxNCtiaHdRazkyT TlMMERGMFM1aGlMMlNSWlA4elRFY3NZaUFwdnI1K3ZXUy9tVHlncTdWdFAKM1NRdDBYVG82NUt3 SkFsWjgwdGl4R01yQWFUdkxtckh0aGk3dXRPS01vTGZHa0g1RFlIcmIvd1RMM0ZRUGswSgoyREF YL3Y4RHJ6YlNQQ2hGQTd5N2VhZExYYzhvKytCSUFNSXFTYTlWZit5WmU3Q0E0clkrY0VHMHgwZU 1sQ3oyClhXOUR3Q1NqR2NOL0ZpQVBuTHdyWmN4U1FyV2doanlMcmtMSXhXeHlIZDNmK2VMc3dFY 2d4SXV4OGdJRk5kWXQKb1BSU3MwSHQydk9NWGtmcEVxV2dWUHJzSG5LUFNQY1VZbUdsTEpkOGov VDBMOVF1ZjJ1MVFvdXUwZ3pqcnBoKwoycDU0N2xNOFM5b2Z5SnhmSkZZR0xQQ1BIU2paTGVIc20 xVWZXOGtzNWwzSGZrSWdkK0NzREpOckdDN3dOdndICkUwd0xNZz09Cj1VWGw3Ci0tLS0tRU5EIF BHUCBNRVNTQUdFLS0tLS0K X-Developer-Key: i=manos@pitsidianak.is; a=openpgp; fpr=7C721DF9DB3CC7182311C0BF68BC211D47B421E1 Generate bindings for include/linux/hw_random.h. Signed-off-by: Manos Pitsidianakis --- rust/bindings/bindings_helper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 3c8b897041bcef879edefdfb9627ca9cafe90e93..40731a278c1759f2658d04438d0= 51169d074a1ac 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include --=20 2.47.3 From nobody Mon Jun 8 11:05:06 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 5D9853E0C4C; Fri, 29 May 2026 15:50:51 +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=1780069853; cv=none; b=IMSEikAy6V3XAHYygSfbUNnbigU6NKbHLDY/RaA7YzA8zvjXpMzWhxjQBNJu8Yyu9WAS3V4sXorn3FoWkaHdvuTq6eO9ccBkcmhBg2V+Fp6he94oKrY6jiAQ/tHRT9H8ZNjWl5VMtDZG5t6Xn5OgdCT02bKHTQffYfLZJhbgYUg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780069853; c=relaxed/simple; bh=oRUSy6GjfKCGaxtXSkaaWCKqLDZmjWp5yKRFlQ2xNuk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Po3NcFme4pz42wkOKsgYUr1uIVchzE/00glJXsl7o0/maTc/gJ+gGEHHQCRNcuPHfRJoP9uD9NhCSgwF+aEBu7eWvB3Rq06UGyl1itm8ZyZW5E7nsMOS44LtIaQ9KRCiRLMLqj9t71LSm5iFfOyeYjJyH33HzWXbeppQzaRS7Vo= 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=qQlAmHnf; 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="qQlAmHnf" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=pitsidianak.is; s=mailSelector; t=1780069843; bh=oRUSy6GjfKCGaxtXSkaaWCKqLDZmjWp5yKRFlQ2xNuk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From:Subject; b=qQlAmHnfwkidTph/8R5jq+Kt7VbXJQGOUZxLcLgQEk/fhPvT0d5YREQoVWXfCLw1q FS+C0UX3ZkNipTuYd/pxe7mMRHokx2jiQnqyvum4iz1daK7UkGq09ZCHLlwihC8LYI ycqjOJPhC7p/DzDJG2xkHs1d8p0lO7XVun+UpwKJXCTVU0ccIGkXH90qaaOPnsUrhX zne4YvK3xbtpsmVRq4Vn667yaQHpbNLMiq89Nor0hhJ4GAkzKK3neilU9fKTfwMKoH wR+BaUSRp5+46iiY3TsV9X1ZT/viZFAF1TgguTNtVImfcPURcPkPRefVJWQweDdTBp HIZG9opWh1Sf+5jMJ7j2rPl5XElXjuMWd9/ZTbwZugnlICnYd1cSLXOZX2qgbuLHIl noxbQI7MkSLrkuL7gD6N6yGH8958p/mG2G2hnbIKEXO/vd742+eTYTIel5hI0eiK71 WCqVzX0dVZe0gMCKGNw3YdR9QWuz1UR9OeRL3geTnI/xW0Tn/FD/WP5ZP635yxm/8V 4LDt1BeFeMCZDesP5vYMC4WAzDMcX3RgXDAmDAU2bLLOlGozHTs0hfGt41C6uaGgWM 7NO8VyB2w7HWCC0kutm2K1zkFdSQpO5OxtBy3O5nZ++rTRmjvuf7roPfLf/+scc7qS t1xJW70ydB7Mkr0HAlbrwiQg= From: Manos Pitsidianakis Date: Fri, 29 May 2026 18:50:27 +0300 Subject: [PATCH 2/2] rust: add hw_random 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: <20260529-rust-hw_random-virtio-rng-v1-2-b3153dd90311@pitsidianak.is> References: <20260529-rust-hw_random-virtio-rng-v1-0-b3153dd90311@pitsidianak.is> In-Reply-To: <20260529-rust-hw_random-virtio-rng-v1-0-b3153dd90311@pitsidianak.is> To: Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Herbert Xu Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-crypto@vger.kernel.org, manos.pitsidianakis@linaro.org X-Developer-Signature: v=1; a=openpgp-sha256; l=12364; i=manos@pitsidianak.is; h=from:subject:message-id; bh=oRUSy6GjfKCGaxtXSkaaWCKqLDZmjWp5yKRFlQ2xNuk=; b=LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tCgpvd0VCYlFLUy9aQU5Bd0FLQVhjcHgzQi9mZ 25RQWNzbVlnQnFHYlhNUmtXNWVQQ3R1bHRySnU4ZHhYbFo4QUhyCnRTOFh0a2kvUENjNUJST0U4 U09KQWpNRUFBRUtBQjBXSVFUTVhCdE9SS0JXODRkd0hSQjNLY2R3ZjM0SjBBVUMKYWhtMXpBQUt DUkIzS2Nkd2YzNEowTHd2RC85d1pTVVQydEUva3VEZUtDUlovL1lQZVlaNVMrQzV5c1pHaWVVcQ p3cTJCVjdqeUhJUGZ1OU5GOXcxNUp1RjZrTGxSa1RHRlBGTHNpUHlIUjcrVFZ5d0VEdDB4b2Zaa EVJdFoySGFvCi9YVlpvMlRBc3RmL0N2OEtTTGEwczlOK0VmZnl6dEZLOGR4V1h4MzFhQWZsOG9Q SjRhNW8rQnpWSHQ3bVNQdUUKQ245L1V1VTZLQ0JkVGRqRkthaWdjalpKWDhHcG5Mbk80SzhkVDZ wUjBKZ1lTYlBFTmhNZDMrRGJWUStTbnlvdgpnOHNGaXl0eGxUZkJGV0g4Ky9wRTg2UjJNaEl1UD hVQ2VVWlZqaldsRDIvOEFTQUhKd0dPZ2RNemZLY3R5eTdnCkZML2s5dTRxaDhUOWlGR0NPYXJIQ ys0dDh6WGFUS0ViVHhjZ0NMTkpUZ3NrTzN3K2ZDOFB6RVFhRHpxcjhBamYKSkpDUlZOb1d3QnMz UVhFOTlaTEVVTkVhYmlkcFBrOU1Fa2lkUG1CYnlHQlM5elRxZW1QNnFPNFVxNk5Ec3R1bgpXbVc 1cmUwdW5CTHNLOUcwMjhyaHJVdVQxQlN0bFhxTUtKVWVHdmJxUGdlVWRUaTI2TFdURmg5QlZ3ME kxUzZmCnJwbUlpZE5ocDUranVHNDBnNW1DSnRkVW9YemVRRDRpcWZnZTcxUjhvQ0hENlhPeWI1Q 0dIb1p3NFJZVlQ2MVcKaGZhWXBWWEN0RUhVa0F3dmJ0T3NyWTVSVWxmTW9zNy82U1MweFhKSVk0 K3ovTkdYc2FZZUplWnUvWkZhU3dZRAptNjRhcC85Q3k4cWJIMmMySG1SR2VFc3pzeklEUFo1ZW1 CSzlSNS9NcTQ0amlHOURqWEVxM0tEYms5c2thak1LCmMzR0c3UT09Cj1qSCtUCi0tLS0tRU5EIF BHUCBNRVNTQUdFLS0tLS0K X-Developer-Key: i=manos@pitsidianak.is; a=openpgp; fpr=7C721DF9DB3CC7182311C0BF68BC211D47B421E1 Add abstraction for the hardware random number generator core subsystem. The registration is guarded by an atomic boolean, because we cannot yet use IRQ disabling spinlocks in Rust. Once they are supported, we should switch to that, because it's theoretically possible to construct a data race. In practice I do not think it's possible, since registration happens once in driver probe and unregistration happens on driver teardown; there shouldn't be multiple threads doing their own thing in both cases. Signed-off-by: Manos Pitsidianakis --- MAINTAINERS | 8 ++ rust/kernel/hw_random.rs | 320 +++++++++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/lib.rs | 2 + 3 files changed, 330 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4f60b323c796fc0968fd67d1c7afee6802990572..a3b372ccbd07c4ae2c735ba31f2= acf40472b384a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11304,6 +11304,14 @@ F: Documentation/devicetree/bindings/rng/ F: drivers/char/hw_random/ F: include/linux/hw_random.h =20 +HARDWARE RANDOM NUMBER GENERATOR CORE [RUST] +M: Manos Pitsidianakis +M: Herbert Xu +L: linux-crypto@vger.kernel.org +L: rust-for-linux@vger.kernel.org +S: Maintained +F: rust/kernel/hw_random.rs + HARDWARE SPINLOCK CORE M: Bjorn Andersson R: Baolin Wang diff --git a/rust/kernel/hw_random.rs b/rust/kernel/hw_random.rs new file mode 100644 index 0000000000000000000000000000000000000000..29fc180b4a3b4157a45c8fdb2d9= 4bf1d9d781a3c --- /dev/null +++ b/rust/kernel/hw_random.rs @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0 +// Author: Manos Pitsidianakis + +//! Hardware Random Number Generators +//! +//! This module provides an abstraction for implementing a hardware random= number generator and +//! using it with the kernel's `hw_random` system. +//! +//! # Example +//! +//! ```no_run +//!# fn no_run() { +//!# use kernel::hw_random::*; +//!# use kernel::str::CString; +//!# use kernel::prelude::*; +//! #[pin_data] +//! struct ExampleHwRng {} +//! +//! #[vtable] +//! impl HwRngImpl for ExampleHwRng { +//! fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()= > { +//! // write zeroes - in your driver, this should write actual dat= a from your hardware. +//! data.write(&[0_u8; 8]); +//! Ok(()) +//! } +//! } +//! +//! let name =3D CString::try_from(c"example_hwrng").unwrap(); +//! let my_rng =3D KBox::pin_init( +//! HwRng::new( +//! name, +//! 0, +//! try_pin_init!(ExampleHwRng {}) +//! ), +//! GFP_KERNEL +//! ).unwrap(); +//! // Register `my_rng`: after this succeeds, the kernel may call our `Hw= RngImpl` method at any +//! // time. +//! my_rng.register().unwrap(); +//! +//! // ... +//! +//! my_rng.unregister(); +//!# } +//!``` + +use crate::{ + error::{ + from_result, // + to_result, // + VTABLE_DEFAULT_ERROR, // + }, + prelude::*, // + str::{ + CString, // + }, + types::{ + Opaque, // + }, +}; + +use core::{ + ffi::{ + c_int, // + c_ushort, // + c_void, // + }, + mem::{ + MaybeUninit, // + }, + ptr::{ + slice_from_raw_parts, // + slice_from_raw_parts_mut, // + }, + sync::atomic::{ + AtomicBool, // + Ordering, // + }, +}; + +use pin_init::pin_init_from_closure; + +/// A buffer to write random bytes in using [`Buffer::write`] that tracks = how many bytes were +/// written. +/// +/// See also [`HwRngImpl::read`]. +pub struct Buffer<'a> { + inner: &'a mut [MaybeUninit], + written: usize, +} + +impl Buffer<'_> { + /// Returns `true` if the buffer has been filled. + #[inline] + pub const fn is_empty(&self) -> bool { + self.written =3D=3D self.inner.len() + } + + /// Returns the number of bytes that can be written. + #[inline] + pub const fn len(&self) -> usize { + self.inner.len() - self.written + } + + /// Writes bytes from `buf` into buffer and returns the amount of byte= s written. + #[inline] + pub fn write(&mut self, buf: &[u8]) -> usize { + let to_copy =3D self.len().min(buf.len()); + let ptr =3D buf.as_ptr(); + // SAFETY: u8 and MaybeUninit have the same layout + let buf =3D unsafe { &*slice_from_raw_parts(ptr.cast::>(), to_copy) }; + self.inner[self.written..][..to_copy].copy_from_slice(buf); + self.written +=3D to_copy; + to_copy + } +} + +/// An adapter type for the registration of hardware random number generat= ors drivers. +/// +/// [`struct hwrng`]: srctree/include/linux/hw_random.h +#[pin_data(PinnedDrop)] +pub struct HwRng { + #[pin] + registration: Opaque, + registered: AtomicBool, + #[pin] + name: CString, + #[pin] + inner: T, +} + +impl core::ops::Deref for HwRng { + type Target =3D T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +// SAFETY: HwRng contains a `*const u8` reference but it is opaque for us = in Rust. +unsafe impl Send for HwRng {} + +// SAFETY: `HwRng` has no interior mutability from Rust, and C manages it = with the rng_mutex lock. +unsafe impl Sync for HwRng {} + +#[pinned_drop] +impl PinnedDrop for HwRng { + fn drop(self: Pin<&mut Self>) { + self.unregister(); + } +} + +#[vtable] +/// Trait for the implementation of hardware RNGs. +pub trait HwRngImpl: Send + Sync { + #[inline] + /// Initialization callback, can be optionally implemented. + fn init(&self) -> Result { + build_error!(VTABLE_DEFAULT_ERROR) + } + + #[inline] + /// Cleanup callback, can be optionally implemented. + fn cleanup(&self) { + build_error!(VTABLE_DEFAULT_ERROR) + } + + /// Places random bytes in `data`. + fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()>; +} + +impl HwRng { + /// Create a new [`HwRng`] without registering it. + pub fn new( + name: CString, + quality: c_ushort, + inner: impl PinInit, + ) -> impl PinInit { + // We use pin_init_from_closure because we need to store the `slot= ` address as `priv` field + // of `hwrng` struct. + + // SAFETY: + // - when the closure returns `Ok(())`, then it has successfully i= nitialized all fields, + // - when it returns `Err(e)`, it does not need to perform any cle= anup. + unsafe { + pin_init_from_closure(move |slot: *mut Self| { + inner.__pinned_init(&raw mut (*slot).inner)?; + + let registration =3D (&raw mut (*slot).registration).cast:= :(); + registration.write(bindings::hwrng { + name: name.as_char_ptr(), + read: Some(Self::read_callback), + init: if ::HAS_INIT { + Some(Self::init_callback) + } else { + None + }, + cleanup: if ::HAS_CLEANUP { + Some(Self::cleanup_callback) + } else { + None + }, + quality, + priv_: slot as usize, + ..Default::default() + }); + + let name_ptr =3D &raw mut (*slot).name; + name_ptr.write(name); + + let registered =3D &raw mut (*slot).registered; + registered.write(AtomicBool::new(false)); + + // All fields of `HwRng` have been initialized + Ok(()) + }) + } + } + + /// Register `self` with the `hwrng` subsystem. + /// + /// After this function successfully returns, the `hwrng` subsystem ca= n start calling the + /// [`HwRngImpl`] methods at any time. + /// + /// [`hwrng_register`]: srctree/include/linux/hw_random.h + #[inline] + #[doc(alias =3D "hwrng_register")] + pub fn register(&self) -> Result { + if self + .registered + .compare_exchange(false, true, Ordering::SeqCst, Ordering::Acq= uire) + .is_ok() + { + // SAFETY: `registration` is properly initialized. + if let Err(err) =3D to_result(unsafe { + bindings::hwrng_register(self.registration.get().cast::()) + }) { + self.registered.store(false, Ordering::Release); + return Err(err); + } + } + Ok(()) + } + + /// Unregister `self` from `hwrng` subsystem. + /// + /// [`hwrng_unregister`]: srctree/include/linux/hw_random.h + #[inline] + #[doc(alias =3D "hwrng_unregister")] + pub fn unregister(&self) { + if self + .registered + .compare_exchange(true, false, Ordering::SeqCst, Ordering::Acq= uire) + .is_ok() + { + // SAFETY: Since `registration` is properly initialized and re= gistered, destroying is + // safe. + unsafe { + bindings::hwrng_unregister(self.registration.get().cast::<= bindings::hwrng>()) + }; + } + } +} + +impl HwRng { + extern "C" fn init_callback(ptr: *mut bindings::hwrng) -> c_int { + // SAFETY: we set `priv_` as the value of `*mut Self` when initial= izing. + let priv_ =3D unsafe { (*ptr).priv_ }; + let this_ptr =3D priv_ as *mut Self; + + // SAFETY: we set `inner` to point to a valid `T` when initializin= g. + let inner: &T =3D unsafe { &(*this_ptr).inner }; + from_result(|| { + inner.init()?; + Ok(0) + }) + } + + extern "C" fn cleanup_callback(ptr: *mut bindings::hwrng) { + // SAFETY: we set `priv_` as the value of `*mut Self` when initial= izing. + let priv_ =3D unsafe { (*ptr).priv_ }; + let this_ptr =3D priv_ as *mut Self; + + // SAFETY: we set `inner` to point to a valid `T` when initializin= g. + let inner: &T =3D unsafe { &(*this_ptr).inner }; + inner.cleanup(); + } + + extern "C" fn read_callback( + ptr: *mut bindings::hwrng, + data: *mut c_void, + max: usize, + wait: bool, + ) -> c_int { + if data.is_null() || max =3D=3D 0 { + return 0; + } + + // SAFETY: we set `priv_` as the value of `*mut Self` when initial= izing. + let priv_ =3D unsafe { (*ptr).priv_ }; + let this_ptr =3D priv_ as *mut Self; + + let buf_ptr =3D slice_from_raw_parts_mut(data.cast::>(), max); + // SAFETY: By the hw_random API contract, data points to a bytes b= uffer `max` bytes long. + let buf_ref =3D unsafe { &mut *buf_ptr }; + + let mut buffer =3D Buffer { + inner: buf_ref, + written: 0, + }; + + // SAFETY: we set `inner` to point to a valid `T` when initializin= g. + let inner: &T =3D unsafe { &(*this_ptr).inner }; + from_result(|| { + inner.read(&mut buffer, wait)?; + Ok(buffer.written.try_into().unwrap_or(c_int::MAX)) + }) + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index ea08641919c26faba97cf5dd9b67b0df55fcd698..096b6d9d57d20612864289e87a3= 59331058fb01c 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -74,6 +74,8 @@ pub mod fs; #[cfg(CONFIG_GPU_BUDDY =3D "y")] pub mod gpu; +#[cfg(CONFIG_HW_RANDOM =3D "y")] +pub mod hw_random; #[cfg(CONFIG_I2C =3D "y")] pub mod i2c; pub mod id_pool; --=20 2.47.3