Skip to content

Commit fa19442

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 6387ac8 commit fa19442

File tree

3 files changed

+223
-0
lines changed

3 files changed

+223
-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: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
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 max 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+
let this = unsafe { self.get_unchecked_mut() };
72+
73+
if this.registered {
74+
return Err(Error::EINVAL);
75+
}
76+
77+
let data_pointer = <T::Data as PointerWrapper>::into_pointer(data);
78+
79+
// The registration is left uninitialized when registration fails to indicate failure.
80+
let mut guard = ScopeGuard::new_with_data(this, |this| {
81+
if !this.registered {
82+
let hwrng = unsafe { &mut *this.hwrng.get() };
83+
*hwrng = bindings::hwrng::default();
84+
}
85+
});
86+
87+
// SAFETY: registration is pinned and contains allocated and set to zero `bindings::hwrng` structure.
88+
Self::init_hwrng(
89+
unsafe { &mut *guard.hwrng.get() },
90+
name,
91+
quality,
92+
data_pointer,
93+
);
94+
95+
// SAFETY: `bindings::hwrng` is initialized above which guarantees safety.
96+
to_result(|| unsafe { bindings::hwrng_register(guard.hwrng.get()) })?;
97+
98+
guard.registered = true;
99+
Ok(())
100+
}
101+
102+
fn init_hwrng(
103+
hwrng: &mut bindings::hwrng,
104+
name: &CStr,
105+
quality: u16,
106+
data: *const core::ffi::c_void,
107+
) {
108+
hwrng.name = <&CStr>::clone(&name).as_char_ptr();
109+
110+
hwrng.init = if T::TO_USE.init {
111+
Some(init_callback::<T>)
112+
} else {
113+
None
114+
};
115+
hwrng.cleanup = if T::TO_USE.cleanup {
116+
Some(cleanup_callback::<T>)
117+
} else {
118+
None
119+
};
120+
hwrng.data_present = None;
121+
hwrng.data_read = None;
122+
hwrng.read = Some(read_callback::<T>);
123+
124+
hwrng.priv_ = data as _;
125+
hwrng.quality = quality;
126+
127+
// SAFETY: All fields are properly initialized as
128+
// remaining fields `list`, `ref` and `cleanup_done` are already
129+
// zeroed by `bindings::hwrng::default()` call.
130+
}
131+
}
132+
133+
impl<T: Operations> Default for Registration<T> {
134+
fn default() -> Self {
135+
Self::new()
136+
}
137+
}
138+
139+
/// Represents which callbacks of [`struct hwrng`] should be populated with pointers.
140+
pub struct ToUse {
141+
/// The `init` field of [`struct hwrng`].
142+
pub init: bool,
143+
144+
/// The `cleanup` field of [`struct hwrng`].
145+
pub cleanup: bool,
146+
}
147+
148+
/// A constant version where all values are to set to `false`, that is, all supported fields will
149+
/// be set to null pointers.
150+
pub const USE_NONE: ToUse = ToUse {
151+
init: false,
152+
cleanup: false,
153+
};
154+
155+
/// Defines the [`Operations::TO_USE`] field based on a list of fields to be populated.
156+
#[macro_export]
157+
macro_rules! declare_hwrng_operations {
158+
() => {
159+
const TO_USE: $crate::hwrng::ToUse = $crate::hwrng::USE_NONE;
160+
};
161+
($($i:ident),+) => {
162+
const TO_USE: kernel::hwrng::ToUse =
163+
$crate::hwrng::ToUse {
164+
$($i: true),+ ,
165+
..$crate::hwrng::USE_NONE
166+
};
167+
};
168+
}
169+
170+
unsafe extern "C" fn init_callback<T: Operations>(rng: *mut bindings::hwrng) -> c_types::c_int {
171+
from_kernel_result! {
172+
// SAFETY: `priv` private data field was initialized during creation of
173+
// the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
174+
// called once the driver is registered.
175+
let data = unsafe { T::Data::borrow((*rng).priv_ as *const core::ffi::c_void) };
176+
T::init(data)?;
177+
Ok(0)
178+
}
179+
}
180+
181+
unsafe extern "C" fn cleanup_callback<T: Operations>(rng: *mut bindings::hwrng) {
182+
// SAFETY: `priv` private data field was initialized during creation of
183+
// the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
184+
// called once the driver is registered.
185+
let data = unsafe { T::Data::borrow((*rng).priv_ as *const core::ffi::c_void) };
186+
T::cleanup(data);
187+
}
188+
189+
unsafe extern "C" fn read_callback<T: Operations>(
190+
rng: *mut bindings::hwrng,
191+
data: *mut c_types::c_void,
192+
max: usize,
193+
wait: bindings::bool_,
194+
) -> c_types::c_int {
195+
from_kernel_result! {
196+
// SAFETY: `priv` private data field was initialized during creation of
197+
// the `bindings::hwrng` in `Self::init_hwrng` method. This callback is only
198+
// called once the driver is registered.
199+
let drv_data = unsafe { T::Data::borrow((*rng).priv_ as *const core::ffi::c_void) };
200+
201+
// SAFETY: Slice is created from `data` and `max` arguments that are C's buffer
202+
// along with its size in bytes that are safe for this conversion.
203+
let buffer = unsafe { from_raw_parts_mut(data as *mut c_types::c_char, max) };
204+
let ret = T::read(drv_data, buffer, wait)?;
205+
Ok(ret as _)
206+
}
207+
}
208+
209+
// SAFETY: `Registration` does not expose any of its state across threads.
210+
unsafe impl<T: Operations> Sync for Registration<T> {}
211+
212+
impl<T: Operations> Drop for Registration<T> {
213+
/// Removes the registration from the kernel if it has completed successfully before.
214+
fn drop(&mut self) {
215+
// SAFETY: The instance of Registration<T> is unregistered only
216+
// after being initialized and registered before.
217+
if self.registered {
218+
unsafe { bindings::hwrng_unregister(self.hwrng.get()) };
219+
}
220+
}
221+
}

rust/kernel/lib.rs

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

0 commit comments

Comments
 (0)