xref: /linux/rust/kernel/module_param.rs (revision c84d574698bad2c02aad506dfe712f83cbe3b771)
10b08fc29SAndreas Hindborg // SPDX-License-Identifier: GPL-2.0
20b08fc29SAndreas Hindborg 
30b08fc29SAndreas Hindborg //! Support for module parameters.
40b08fc29SAndreas Hindborg //!
50b08fc29SAndreas Hindborg //! C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h)
60b08fc29SAndreas Hindborg 
70b08fc29SAndreas Hindborg use crate::prelude::*;
80b08fc29SAndreas Hindborg use crate::str::BStr;
90b08fc29SAndreas Hindborg use bindings;
100b08fc29SAndreas Hindborg use kernel::sync::SetOnce;
110b08fc29SAndreas Hindborg 
120b08fc29SAndreas Hindborg /// Newtype to make `bindings::kernel_param` [`Sync`].
130b08fc29SAndreas Hindborg #[repr(transparent)]
140b08fc29SAndreas Hindborg #[doc(hidden)]
150b08fc29SAndreas Hindborg pub struct KernelParam(bindings::kernel_param);
160b08fc29SAndreas Hindborg 
170b08fc29SAndreas Hindborg impl KernelParam {
180b08fc29SAndreas Hindborg     #[doc(hidden)]
new(val: bindings::kernel_param) -> Self190b08fc29SAndreas Hindborg     pub const fn new(val: bindings::kernel_param) -> Self {
200b08fc29SAndreas Hindborg         Self(val)
210b08fc29SAndreas Hindborg     }
220b08fc29SAndreas Hindborg }
230b08fc29SAndreas Hindborg 
240b08fc29SAndreas Hindborg // SAFETY: C kernel handles serializing access to this type. We never access it
250b08fc29SAndreas Hindborg // from Rust module.
260b08fc29SAndreas Hindborg unsafe impl Sync for KernelParam {}
270b08fc29SAndreas Hindborg 
280b08fc29SAndreas Hindborg /// Types that can be used for module parameters.
290b08fc29SAndreas Hindborg // NOTE: This trait is `Copy` because drop could produce unsoundness during teardown.
300b08fc29SAndreas Hindborg pub trait ModuleParam: Sized + Copy {
310b08fc29SAndreas Hindborg     /// Parse a parameter argument into the parameter value.
try_from_param_arg(arg: &BStr) -> Result<Self>320b08fc29SAndreas Hindborg     fn try_from_param_arg(arg: &BStr) -> Result<Self>;
330b08fc29SAndreas Hindborg }
340b08fc29SAndreas Hindborg 
350b08fc29SAndreas Hindborg /// Set the module parameter from a string.
360b08fc29SAndreas Hindborg ///
370b08fc29SAndreas Hindborg /// Used to set the parameter value at kernel initialization, when loading
380b08fc29SAndreas Hindborg /// the module or when set through `sysfs`.
390b08fc29SAndreas Hindborg ///
400b08fc29SAndreas Hindborg /// See `struct kernel_param_ops.set`.
410b08fc29SAndreas Hindborg ///
420b08fc29SAndreas Hindborg /// # Safety
430b08fc29SAndreas Hindborg ///
440b08fc29SAndreas Hindborg /// - If `val` is non-null then it must point to a valid null-terminated string that must be valid
450b08fc29SAndreas Hindborg ///   for reads for the duration of the call.
460b08fc29SAndreas Hindborg /// - `param` must be a pointer to a `bindings::kernel_param` initialized by the rust module macro.
470b08fc29SAndreas Hindborg ///   The pointee must be valid for reads for the duration of the call.
480b08fc29SAndreas Hindborg ///
490b08fc29SAndreas Hindborg /// # Note
500b08fc29SAndreas Hindborg ///
510b08fc29SAndreas Hindborg /// - The safety requirements are satisfied by C API contract when this function is invoked by the
520b08fc29SAndreas Hindborg ///   module subsystem C code.
530b08fc29SAndreas Hindborg /// - Currently, we only support read-only parameters that are not readable from `sysfs`. Thus, this
540b08fc29SAndreas Hindborg ///   function is only called at kernel initialization time, or at module load time, and we have
550b08fc29SAndreas Hindborg ///   exclusive access to the parameter for the duration of the function.
560b08fc29SAndreas Hindborg ///
570b08fc29SAndreas Hindborg /// [`module!`]: macros::module
set_param<T>(val: *const c_char, param: *const bindings::kernel_param) -> c_int where T: ModuleParam,580b08fc29SAndreas Hindborg unsafe extern "C" fn set_param<T>(val: *const c_char, param: *const bindings::kernel_param) -> c_int
590b08fc29SAndreas Hindborg where
600b08fc29SAndreas Hindborg     T: ModuleParam,
610b08fc29SAndreas Hindborg {
620b08fc29SAndreas Hindborg     // NOTE: If we start supporting arguments without values, val _is_ allowed
630b08fc29SAndreas Hindborg     // to be null here.
640b08fc29SAndreas Hindborg     if val.is_null() {
650b08fc29SAndreas Hindborg         // TODO: Use pr_warn_once available.
660b08fc29SAndreas Hindborg         crate::pr_warn!("Null pointer passed to `module_param::set_param`");
670b08fc29SAndreas Hindborg         return EINVAL.to_errno();
680b08fc29SAndreas Hindborg     }
690b08fc29SAndreas Hindborg 
700b08fc29SAndreas Hindborg     // SAFETY: By function safety requirement, val is non-null, null-terminated
710b08fc29SAndreas Hindborg     // and valid for reads for the duration of this function.
720b08fc29SAndreas Hindborg     let arg = unsafe { CStr::from_char_ptr(val) };
73*c84d5746SLinus Torvalds     let arg: &BStr = arg.as_ref();
740b08fc29SAndreas Hindborg 
750b08fc29SAndreas Hindborg     crate::error::from_result(|| {
760b08fc29SAndreas Hindborg         let new_value = T::try_from_param_arg(arg)?;
770b08fc29SAndreas Hindborg 
780b08fc29SAndreas Hindborg         // SAFETY: By function safety requirements, this access is safe.
790b08fc29SAndreas Hindborg         let container = unsafe { &*((*param).__bindgen_anon_1.arg.cast::<SetOnce<T>>()) };
800b08fc29SAndreas Hindborg 
810b08fc29SAndreas Hindborg         container
820b08fc29SAndreas Hindborg             .populate(new_value)
830b08fc29SAndreas Hindborg             .then_some(0)
840b08fc29SAndreas Hindborg             .ok_or(kernel::error::code::EEXIST)
850b08fc29SAndreas Hindborg     })
860b08fc29SAndreas Hindborg }
870b08fc29SAndreas Hindborg 
880b08fc29SAndreas Hindborg macro_rules! impl_int_module_param {
890b08fc29SAndreas Hindborg     ($ty:ident) => {
900b08fc29SAndreas Hindborg         impl ModuleParam for $ty {
910b08fc29SAndreas Hindborg             fn try_from_param_arg(arg: &BStr) -> Result<Self> {
920b08fc29SAndreas Hindborg                 <$ty as crate::str::parse_int::ParseInt>::from_str(arg)
930b08fc29SAndreas Hindborg             }
940b08fc29SAndreas Hindborg         }
950b08fc29SAndreas Hindborg     };
960b08fc29SAndreas Hindborg }
970b08fc29SAndreas Hindborg 
980b08fc29SAndreas Hindborg impl_int_module_param!(i8);
990b08fc29SAndreas Hindborg impl_int_module_param!(u8);
1000b08fc29SAndreas Hindborg impl_int_module_param!(i16);
1010b08fc29SAndreas Hindborg impl_int_module_param!(u16);
1020b08fc29SAndreas Hindborg impl_int_module_param!(i32);
1030b08fc29SAndreas Hindborg impl_int_module_param!(u32);
1040b08fc29SAndreas Hindborg impl_int_module_param!(i64);
1050b08fc29SAndreas Hindborg impl_int_module_param!(u64);
1060b08fc29SAndreas Hindborg impl_int_module_param!(isize);
1070b08fc29SAndreas Hindborg impl_int_module_param!(usize);
1080b08fc29SAndreas Hindborg 
1090b08fc29SAndreas Hindborg /// A wrapper for kernel parameters.
1100b08fc29SAndreas Hindborg ///
1110b08fc29SAndreas Hindborg /// This type is instantiated by the [`module!`] macro when module parameters are
1120b08fc29SAndreas Hindborg /// defined. You should never need to instantiate this type directly.
1130b08fc29SAndreas Hindborg ///
1140b08fc29SAndreas Hindborg /// Note: This type is `pub` because it is used by module crates to access
1150b08fc29SAndreas Hindborg /// parameter values.
1160b08fc29SAndreas Hindborg pub struct ModuleParamAccess<T> {
1170b08fc29SAndreas Hindborg     value: SetOnce<T>,
1180b08fc29SAndreas Hindborg     default: T,
1190b08fc29SAndreas Hindborg }
1200b08fc29SAndreas Hindborg 
1210b08fc29SAndreas Hindborg // SAFETY: We only create shared references to the contents of this container,
1220b08fc29SAndreas Hindborg // so if `T` is `Sync`, so is `ModuleParamAccess`.
1230b08fc29SAndreas Hindborg unsafe impl<T: Sync> Sync for ModuleParamAccess<T> {}
1240b08fc29SAndreas Hindborg 
1250b08fc29SAndreas Hindborg impl<T> ModuleParamAccess<T> {
1260b08fc29SAndreas Hindborg     #[doc(hidden)]
new(default: T) -> Self1270b08fc29SAndreas Hindborg     pub const fn new(default: T) -> Self {
1280b08fc29SAndreas Hindborg         Self {
1290b08fc29SAndreas Hindborg             value: SetOnce::new(),
1300b08fc29SAndreas Hindborg             default,
1310b08fc29SAndreas Hindborg         }
1320b08fc29SAndreas Hindborg     }
1330b08fc29SAndreas Hindborg 
1340b08fc29SAndreas Hindborg     /// Get a shared reference to the parameter value.
1350b08fc29SAndreas Hindborg     // Note: When sysfs access to parameters are enabled, we have to pass in a
1360b08fc29SAndreas Hindborg     // held lock guard here.
value(&self) -> &T1370b08fc29SAndreas Hindborg     pub fn value(&self) -> &T {
1380b08fc29SAndreas Hindborg         self.value.as_ref().unwrap_or(&self.default)
1390b08fc29SAndreas Hindborg     }
1400b08fc29SAndreas Hindborg 
1410b08fc29SAndreas Hindborg     /// Get a mutable pointer to `self`.
1420b08fc29SAndreas Hindborg     ///
1430b08fc29SAndreas Hindborg     /// NOTE: In most cases it is not safe deref the returned pointer.
as_void_ptr(&self) -> *mut c_void1440b08fc29SAndreas Hindborg     pub const fn as_void_ptr(&self) -> *mut c_void {
1450b08fc29SAndreas Hindborg         core::ptr::from_ref(self).cast_mut().cast()
1460b08fc29SAndreas Hindborg     }
1470b08fc29SAndreas Hindborg }
1480b08fc29SAndreas Hindborg 
1490b08fc29SAndreas Hindborg #[doc(hidden)]
1500b08fc29SAndreas Hindborg /// Generate a static [`kernel_param_ops`](srctree/include/linux/moduleparam.h) struct.
1510b08fc29SAndreas Hindborg ///
1520b08fc29SAndreas Hindborg /// # Examples
1530b08fc29SAndreas Hindborg ///
1540b08fc29SAndreas Hindborg /// ```ignore
1550b08fc29SAndreas Hindborg /// make_param_ops!(
1560b08fc29SAndreas Hindborg ///     /// Documentation for new param ops.
1570b08fc29SAndreas Hindborg ///     PARAM_OPS_MYTYPE, // Name for the static.
1580b08fc29SAndreas Hindborg ///     MyType // A type which implements [`ModuleParam`].
1590b08fc29SAndreas Hindborg /// );
1600b08fc29SAndreas Hindborg /// ```
1610b08fc29SAndreas Hindborg macro_rules! make_param_ops {
1620b08fc29SAndreas Hindborg     ($ops:ident, $ty:ty) => {
1630b08fc29SAndreas Hindborg         #[doc(hidden)]
1640b08fc29SAndreas Hindborg         pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
1650b08fc29SAndreas Hindborg             flags: 0,
1660b08fc29SAndreas Hindborg             set: Some(set_param::<$ty>),
1670b08fc29SAndreas Hindborg             get: None,
1680b08fc29SAndreas Hindborg             free: None,
1690b08fc29SAndreas Hindborg         };
1700b08fc29SAndreas Hindborg     };
1710b08fc29SAndreas Hindborg }
1720b08fc29SAndreas Hindborg 
1730b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_I8, i8);
1740b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_U8, u8);
1750b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_I16, i16);
1760b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_U16, u16);
1770b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_I32, i32);
1780b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_U32, u32);
1790b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_I64, i64);
1800b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_U64, u64);
1810b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_ISIZE, isize);
1820b08fc29SAndreas Hindborg make_param_ops!(PARAM_OPS_USIZE, usize);
183