Skip to content

Commit d74e55e

Browse files
committed
Implement array and string parameters
1 parent 35b9d14 commit d74e55e

File tree

3 files changed

+409
-97
lines changed

3 files changed

+409
-97
lines changed

rust/kernel/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//! do so first instead of bypassing this crate.
1313
1414
#![no_std]
15-
#![feature(allocator_api, alloc_error_handler)]
15+
#![feature(allocator_api, alloc_error_handler, const_fn, const_mut_refs)]
1616
#![deny(clippy::complexity)]
1717
#![deny(clippy::correctness)]
1818
#![deny(clippy::perf)]
@@ -36,7 +36,10 @@ pub mod chrdev;
3636
mod error;
3737
pub mod file_operations;
3838
pub mod miscdev;
39+
40+
#[doc(hidden)]
3941
pub mod module_param;
42+
4043
pub mod prelude;
4144
pub mod printk;
4245
pub mod random;

rust/kernel/module_param.rs

+189-12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ use core::fmt::Write;
1515
///
1616
/// [`PAGE_SIZE`]: `crate::PAGE_SIZE`
1717
pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
18+
/// The `ModuleParam` will be used by the kernel module through this type.
19+
///
20+
/// This may differ from `Self` if, for example, `Self` needs to track
21+
/// ownership without exposing it or allocate extra space for other possible
22+
/// parameter values. See [`StringParam`] or [`ArrayParam`] for examples.
23+
type Value: ?Sized;
24+
1825
/// Whether the parameter is allowed to be set without an argument.
1926
///
2027
/// Setting this to `true` allows the parameter to be passed without an
@@ -27,7 +34,13 @@ pub trait ModuleParam: core::fmt::Display + core::marker::Sized {
2734
/// `arg == None` indicates that the parameter was passed without an
2835
/// argument. If `NOARG_ALLOWED` is set to `false` then `arg` is guaranteed
2936
/// to always be `Some(_)`.
30-
fn try_from_param_arg(arg: Option<&[u8]>) -> Option<Self>;
37+
fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self>;
38+
39+
/// Get the current value of the parameter for use in the kernel module.
40+
///
41+
/// This function should not be used directly. Instead use the wrapper
42+
/// `read` which will be generated by [`module::module`].
43+
fn value(&self) -> &Self::Value;
3144

3245
/// Set the module parameter from a string.
3346
///
@@ -161,17 +174,23 @@ impl_parse_int!(usize);
161174
macro_rules! impl_module_param {
162175
($ty:ident) => {
163176
impl ModuleParam for $ty {
177+
type Value = $ty;
164178
const NOARG_ALLOWED: bool = false;
165179

166-
fn try_from_param_arg(arg: Option<&[u8]>) -> Option<Self> {
180+
fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
167181
let bytes = arg?;
168182
let utf8 = core::str::from_utf8(bytes).ok()?;
169183
<$ty as crate::module_param::ParseInt>::from_str(utf8)
170184
}
185+
186+
fn value(&self) -> &Self::Value {
187+
self
188+
}
171189
}
172190
};
173191
}
174192

193+
#[doc(hidden)]
175194
#[macro_export]
176195
/// Generate a static [`kernel_param_ops`](../../../include/linux/moduleparam.h) struct.
177196
///
@@ -184,27 +203,27 @@ macro_rules! impl_module_param {
184203
/// );
185204
/// ```
186205
macro_rules! make_param_ops {
187-
($ops:ident, $ty:ident) => {
188-
make_param_ops!(
206+
($ops:ident, $ty:ty) => {
207+
$crate::make_param_ops!(
189208
#[doc=""]
190209
$ops,
191210
$ty
192211
);
193212
};
194-
($(#[$meta:meta])* $ops:ident, $ty:ident) => {
213+
($(#[$meta:meta])* $ops:ident, $ty:ty) => {
195214
$(#[$meta])*
196215
///
197216
/// Static [`kernel_param_ops`](../../../include/linux/moduleparam.h)
198217
/// struct generated by [`make_param_ops`].
199-
pub static $ops: crate::bindings::kernel_param_ops = crate::bindings::kernel_param_ops {
200-
flags: if <$ty as crate::module_param::ModuleParam>::NOARG_ALLOWED {
201-
crate::bindings::KERNEL_PARAM_OPS_FL_NOARG
218+
pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
219+
flags: if <$ty as $crate::module_param::ModuleParam>::NOARG_ALLOWED {
220+
$crate::bindings::KERNEL_PARAM_OPS_FL_NOARG
202221
} else {
203222
0
204223
},
205-
set: Some(<$ty as crate::module_param::ModuleParam>::set_param),
206-
get: Some(<$ty as crate::module_param::ModuleParam>::get_param),
207-
free: Some(<$ty as crate::module_param::ModuleParam>::free),
224+
set: Some(<$ty as $crate::module_param::ModuleParam>::set_param),
225+
get: Some(<$ty as $crate::module_param::ModuleParam>::get_param),
226+
free: Some(<$ty as $crate::module_param::ModuleParam>::free),
208227
};
209228
};
210229
}
@@ -282,16 +301,21 @@ make_param_ops!(
282301
);
283302

284303
impl ModuleParam for bool {
304+
type Value = bool;
285305
const NOARG_ALLOWED: bool = true;
286306

287-
fn try_from_param_arg(arg: Option<&[u8]>) -> Option<Self> {
307+
fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
288308
match arg {
289309
None => Some(true),
290310
Some(b"y") | Some(b"Y") | Some(b"1") | Some(b"true") => Some(true),
291311
Some(b"n") | Some(b"N") | Some(b"0") | Some(b"false") => Some(false),
292312
_ => None,
293313
}
294314
}
315+
316+
fn value(&self) -> &Self::Value {
317+
self
318+
}
295319
}
296320

297321
make_param_ops!(
@@ -300,3 +324,156 @@ make_param_ops!(
300324
PARAM_OPS_BOOL,
301325
bool
302326
);
327+
328+
/// An array of at __most__ `N` values.
329+
///
330+
/// # Invariant
331+
///
332+
/// The first `self.used` elements of `self.values` are initialized.
333+
pub struct ArrayParam<T, const N: usize> {
334+
values: [core::mem::MaybeUninit<T>; N],
335+
used: usize,
336+
}
337+
338+
impl<T, const N: usize> ArrayParam<T, { N }> {
339+
fn values(&self) -> &[T] {
340+
// SAFETY: The invariant maintained by `ArrayParam` allows us to cast
341+
// the first `self.used` elements to `T`.
342+
unsafe {
343+
&*(&self.values[0..self.used] as *const [core::mem::MaybeUninit<T>] as *const [T])
344+
}
345+
}
346+
}
347+
348+
impl<T: Copy, const N: usize> ArrayParam<T, { N }> {
349+
const fn new() -> Self {
350+
// INVARIANT: The first `self.used` elements of `self.values` are
351+
// initialized.
352+
ArrayParam {
353+
values: [core::mem::MaybeUninit::uninit(); N],
354+
used: 0,
355+
}
356+
}
357+
358+
const fn push(&mut self, val: T) {
359+
if self.used < N {
360+
// INVARIANT: The first `self.used` elements of `self.values` are
361+
// initialized.
362+
self.values[self.used] = core::mem::MaybeUninit::new(val);
363+
self.used += 1;
364+
}
365+
}
366+
367+
/// Create an instance of `ArrayParam` initialized with `vals`.
368+
///
369+
/// This function is only meant to be used in the [`module::module`] macro.
370+
pub const fn create(vals: &[T]) -> Self {
371+
let mut result = ArrayParam::new();
372+
let mut i = 0;
373+
while i < vals.len() {
374+
result.push(vals[i]);
375+
i += 1;
376+
}
377+
result
378+
}
379+
}
380+
381+
impl<T: core::fmt::Display, const N: usize> core::fmt::Display for ArrayParam<T, { N }> {
382+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
383+
for val in self.values() {
384+
write!(f, "{},", val)?;
385+
}
386+
Ok(())
387+
}
388+
}
389+
390+
impl<T: Copy + core::fmt::Display + ModuleParam, const N: usize> ModuleParam
391+
for ArrayParam<T, { N }>
392+
{
393+
type Value = [T];
394+
const NOARG_ALLOWED: bool = false;
395+
396+
fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
397+
arg.and_then(|args| {
398+
let mut result = Self::new();
399+
for arg in args.split(|b| *b == b',') {
400+
result.push(T::try_from_param_arg(Some(arg))?);
401+
}
402+
Some(result)
403+
})
404+
}
405+
406+
fn value(&self) -> &Self::Value {
407+
self.values()
408+
}
409+
}
410+
411+
/// A C-style string parameter.
412+
///
413+
/// The Rust version of the [`charp`] parameter. This type is meant to be
414+
/// used by the [`module::module`] macro, not handled directly. Instead use the
415+
/// `read` method generated by that macro.
416+
///
417+
/// [`charp`]: ../../../include/linux/moduleparam.h
418+
pub enum StringParam {
419+
/// A borrowed parameter value.
420+
///
421+
/// Either the default value (which is static in the module) or borrowed
422+
/// from the original argument buffer used to set the value.
423+
Ref(&'static [u8]),
424+
425+
/// A value that was allocated when the parameter was set.
426+
///
427+
/// The value needs to be freed when the parameter is reset or the module is
428+
/// unloaded.
429+
Owned(alloc::vec::Vec<u8>),
430+
}
431+
432+
impl StringParam {
433+
fn bytes(&self) -> &[u8] {
434+
match self {
435+
StringParam::Ref(bytes) => *bytes,
436+
StringParam::Owned(vec) => &vec[..],
437+
}
438+
}
439+
}
440+
441+
impl core::fmt::Display for StringParam {
442+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
443+
let bytes = self.bytes();
444+
match core::str::from_utf8(bytes) {
445+
Ok(utf8) => write!(f, "{}", utf8),
446+
Err(_) => write!(f, "{:?}", bytes),
447+
}
448+
}
449+
}
450+
451+
impl ModuleParam for StringParam {
452+
type Value = [u8];
453+
const NOARG_ALLOWED: bool = false;
454+
455+
fn try_from_param_arg(arg: Option<&'static [u8]>) -> Option<Self> {
456+
// SAFETY: It is always safe to call [`slab_is_available`](../../../include/linux/slab.h).
457+
let slab_available = unsafe { crate::bindings::slab_is_available() };
458+
arg.map(|arg| {
459+
if slab_available {
460+
let mut vec = alloc::vec::Vec::new();
461+
vec.extend_from_slice(arg);
462+
StringParam::Owned(vec)
463+
} else {
464+
StringParam::Ref(arg)
465+
}
466+
})
467+
}
468+
469+
fn value(&self) -> &Self::Value {
470+
self.bytes()
471+
}
472+
}
473+
474+
make_param_ops!(
475+
/// Rust implementation of [`kernel_param_ops`](../../../include/linux/moduleparam.h)
476+
/// for [`StringParam`].
477+
PARAM_OPS_STR,
478+
StringParam
479+
);

0 commit comments

Comments
 (0)