Skip to content

Commit 75319f5

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 cd969b5 commit 75319f5

File tree

3 files changed

+225
-0
lines changed

3 files changed

+225
-0
lines changed

rust/kernel/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/cdev.h>
44
#include <linux/errname.h>
55
#include <linux/fs.h>
6+
#include <linux/hw_random.h>
67
#include <linux/module.h>
78
#include <linux/random.h>
89
#include <linux/slab.h>

rust/kernel/hwrng.rs

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

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ mod error;
5252
pub mod file;
5353
pub mod file_operations;
5454
pub mod gpio;
55+
pub mod hwrng;
5556
pub mod irq;
5657
pub mod miscdev;
5758
pub mod pages;

0 commit comments

Comments
 (0)