Skip to content

Commit 6d02ddb

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 e2c5979 commit 6d02ddb

File tree

3 files changed

+244
-0
lines changed

3 files changed

+244
-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

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

rust/kernel/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ mod error;
5454
pub mod file;
5555
pub mod file_operations;
5656
pub mod gpio;
57+
pub mod hwrng;
5758
pub mod irq;
5859
pub mod miscdev;
5960
pub mod mm;

0 commit comments

Comments
 (0)