Skip to content

Commit 94b77fd

Browse files
author
Maciej Falkowski
committed
rust: add Hardware Random Number Generator subsystem
This patch adds abstractions over the hwrng subsystem: - trait `hwrng::Operations` that defines operations of a hwrng driver. - declare_hwrng_operations!() macro that populates callback pointers located in hwrng structure. - Registration structure for hwrng's drivers. Signed-off-by: Maciej Falkowski <[email protected]>
1 parent 60f0f3c commit 94b77fd

File tree

3 files changed

+235
-0
lines changed

3 files changed

+235
-0
lines changed

rust/kernel/bindings_helper.h

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <linux/clk.h>
55
#include <linux/errname.h>
66
#include <linux/fs.h>
7+
#include <linux/hw_random.h>
78
#include <linux/module.h>
89
#include <linux/random.h>
910
#include <linux/slab.h>

rust/kernel/hwrng.rs

+233
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Hardware Random Number Generator.
4+
//!
5+
//! C header: [`include/linux/hw_random.h`](../../../../include/linux/hw_random.h)
6+
7+
use alloc::{boxed::Box, slice::from_raw_parts_mut};
8+
9+
use crate::{
10+
bindings, c_types, error::from_kernel_result, str::CStr, to_result, types::PointerWrapper,
11+
Error, Result, ScopeGuard,
12+
};
13+
14+
use core::{cell::UnsafeCell, marker::PhantomData, pin::Pin};
15+
16+
/// This trait is implemented in order to provide callbacks to `struct hwrng`.
17+
pub trait Operations {
18+
/// The methods to use to populate [`struct hwrng`].
19+
const TO_USE: ToUse;
20+
21+
/// The pointer type that will be used to hold user-defined data type.
22+
type Data: PointerWrapper + Send + Sync = ();
23+
24+
/// Initialization callback, can be left undefined.
25+
fn init(_data: <Self::Data as PointerWrapper>::Borrowed<'_>) -> Result {
26+
Err(Error::EINVAL)
27+
}
28+
29+
/// Cleanup callback, can be left undefined.
30+
fn cleanup(_data: Self::Data) {}
31+
32+
/// Read data into the provided buffer.
33+
/// Drivers can fill up to max bytes of data into the buffer.
34+
/// The buffer is aligned for any type and its size is a multiple of 4 and >= 32 bytes.
35+
fn read(
36+
data: <Self::Data as PointerWrapper>::Borrowed<'_>,
37+
buffer: &mut [i8],
38+
wait: bool,
39+
) -> Result<u32>;
40+
}
41+
42+
/// Registration structure for Hardware Random Number Generator driver.
43+
pub struct Registration<T: Operations> {
44+
hwrng: UnsafeCell<bindings::hwrng>,
45+
registered: bool,
46+
_p: PhantomData<T>,
47+
}
48+
49+
impl<T: Operations> Registration<T> {
50+
/// Creates new instance of registration.
51+
///
52+
/// The data must be registered.
53+
pub fn new() -> Self {
54+
Self {
55+
hwrng: UnsafeCell::new(bindings::hwrng::default()),
56+
registered: false,
57+
_p: PhantomData,
58+
}
59+
}
60+
61+
/// Returns a registered and pinned, heap-allocated representation of the registration.
62+
pub fn new_pinned(name: &'static CStr, quality: u16, data: T::Data) -> Result<Pin<Box<Self>>> {
63+
let mut reg = Pin::from(Box::try_new(Self::new())?);
64+
reg.as_mut().register(name, quality, data)?;
65+
Ok(reg)
66+
}
67+
68+
/// Registers a hwrng device within the rest of the kernel.
69+
///
70+
/// It must be pinned because the memory block that represents
71+
/// the registration may be self-referential.
72+
pub fn register(
73+
self: Pin<&mut Self>,
74+
name: &'static CStr,
75+
quality: u16,
76+
data: T::Data,
77+
) -> Result {
78+
// SAFETY: We never move out of `this`.
79+
let this = unsafe { self.get_unchecked_mut() };
80+
81+
if this.registered {
82+
return Err(Error::EINVAL);
83+
}
84+
85+
let data_pointer = data.into_pointer();
86+
87+
// SAFETY: `data_pointer` is never moved and remains valid in the function's scope.
88+
let guard = ScopeGuard::new(|| unsafe {
89+
T::Data::from_pointer(data_pointer);
90+
});
91+
92+
// SAFETY: registration is pinned and contains allocated and set to zero `bindings::hwrng` structure.
93+
Self::init_hwrng(
94+
unsafe { &mut *this.hwrng.get() },
95+
name,
96+
quality,
97+
data_pointer,
98+
);
99+
100+
// SAFETY: `bindings::hwrng` is initialized above which guarantees safety.
101+
to_result(|| unsafe { bindings::hwrng_register(this.hwrng.get()) })?;
102+
103+
this.registered = true;
104+
guard.dismiss();
105+
Ok(())
106+
}
107+
108+
fn init_hwrng(
109+
hwrng: &mut bindings::hwrng,
110+
name: &'static CStr,
111+
quality: u16,
112+
data: *const core::ffi::c_void,
113+
) {
114+
hwrng.name = name.as_char_ptr();
115+
116+
hwrng.init = if T::TO_USE.init {
117+
Some(Self::init_callback)
118+
} else {
119+
None
120+
};
121+
hwrng.cleanup = if T::TO_USE.cleanup {
122+
Some(Self::cleanup_callback)
123+
} else {
124+
None
125+
};
126+
hwrng.data_present = None;
127+
hwrng.data_read = None;
128+
hwrng.read = Some(Self::read_callback);
129+
130+
hwrng.priv_ = data as _;
131+
hwrng.quality = quality;
132+
133+
// SAFETY: All fields are properly initialized as
134+
// remaining fields `list`, `ref` and `cleanup_done` are already
135+
// zeroed by `bindings::hwrng::default()` call.
136+
}
137+
138+
unsafe extern "C" fn init_callback(rng: *mut bindings::hwrng) -> c_types::c_int {
139+
from_kernel_result! {
140+
// SAFETY: `priv` private data field was initialized during creation of
141+
// the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
142+
// called once the driver is registered.
143+
let data = unsafe { T::Data::borrow((*rng).priv_ as *const core::ffi::c_void) };
144+
T::init(data)?;
145+
Ok(0)
146+
}
147+
}
148+
149+
unsafe extern "C" fn cleanup_callback(rng: *mut bindings::hwrng) {
150+
// SAFETY: `priv` private data field was initialized during creation of
151+
// the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
152+
// called once the driver is registered.
153+
let data = unsafe { T::Data::from_pointer((*rng).priv_ as *const core::ffi::c_void) };
154+
T::cleanup(data);
155+
}
156+
157+
unsafe extern "C" fn read_callback(
158+
rng: *mut bindings::hwrng,
159+
data: *mut c_types::c_void,
160+
max: usize,
161+
wait: bindings::bool_,
162+
) -> c_types::c_int {
163+
from_kernel_result! {
164+
// SAFETY: `priv` private data field was initialized during creation of
165+
// the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
166+
// called once the driver is registered.
167+
let drv_data = unsafe { T::Data::borrow((*rng).priv_ as *const core::ffi::c_void) };
168+
169+
// SAFETY: Slice is created from `data` and `max` arguments that are C's buffer
170+
// along with its size in bytes that are safe for this conversion.
171+
let buffer = unsafe { from_raw_parts_mut(data as *mut c_types::c_char, max) };
172+
let ret = T::read(drv_data, buffer, wait)?;
173+
Ok(ret as _)
174+
}
175+
}
176+
}
177+
178+
impl<T: Operations> Default for Registration<T> {
179+
fn default() -> Self {
180+
Self::new()
181+
}
182+
}
183+
184+
/// Represents which callbacks of [`struct hwrng`] should be populated with pointers.
185+
pub struct ToUse {
186+
/// The `init` field of [`struct hwrng`].
187+
pub init: bool,
188+
189+
/// The `cleanup` field of [`struct hwrng`].
190+
pub cleanup: bool,
191+
}
192+
193+
/// A constant version where all values are to set to `false`, that is, all supported fields will
194+
/// be set to null pointers.
195+
pub const USE_NONE: ToUse = ToUse {
196+
init: false,
197+
cleanup: false,
198+
};
199+
200+
/// Defines the [`Operations::TO_USE`] field based on a list of fields to be populated.
201+
#[macro_export]
202+
macro_rules! declare_hwrng_operations {
203+
() => {
204+
const TO_USE: $crate::hwrng::ToUse = $crate::hwrng::USE_NONE;
205+
};
206+
($($i:ident),+) => {
207+
#[allow(clippy::needless_update)]
208+
const TO_USE: kernel::hwrng::ToUse =
209+
$crate::hwrng::ToUse {
210+
$($i: true),+ ,
211+
..$crate::hwrng::USE_NONE
212+
};
213+
};
214+
}
215+
216+
// SAFETY: `Registration` does not expose any of its state across threads.
217+
unsafe impl<T: Operations> Sync for Registration<T> {}
218+
219+
// SAFETY: `Registration` is not restricted to a single thread,
220+
// its `T::Data` is also `Send` so it may be moved to different threads.
221+
#[allow(clippy::non_send_fields_in_send_ty)]
222+
unsafe impl<T: Operations> Send for Registration<T> {}
223+
224+
impl<T: Operations> Drop for Registration<T> {
225+
/// Removes the registration from the kernel if it has completed successfully before.
226+
fn drop(&mut self) {
227+
// SAFETY: The instance of Registration<T> is unregistered only
228+
// after being initialized and registered before.
229+
if self.registered {
230+
unsafe { bindings::hwrng_unregister(self.hwrng.get()) };
231+
}
232+
}
233+
}

rust/kernel/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ mod error;
5555
pub mod file;
5656
pub mod file_operations;
5757
pub mod gpio;
58+
pub mod hwrng;
5859
pub mod irq;
5960
pub mod miscdev;
6061
pub mod mm;

0 commit comments

Comments
 (0)