|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | + |
| 3 | +//! Types for module parameters. |
| 4 | +//! |
| 5 | +//! C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h) |
| 6 | +
|
| 7 | +use crate::prelude::*; |
| 8 | +use crate::str::BStr; |
| 9 | + |
| 10 | +/// Newtype to make `bindings::kernel_param` [`Sync`]. |
| 11 | +#[repr(transparent)] |
| 12 | +#[doc(hidden)] |
| 13 | +pub struct RacyKernelParam(pub ::kernel::bindings::kernel_param); |
| 14 | + |
| 15 | +// SAFETY: C kernel handles serializing access to this type. We never access |
| 16 | +// from Rust module. |
| 17 | +unsafe impl Sync for RacyKernelParam {} |
| 18 | + |
| 19 | +/// Types that can be used for module parameters. |
| 20 | +/// |
| 21 | +/// Note that displaying the type in `sysfs` will fail if |
| 22 | +/// [`Display`](core::fmt::Display) implementation would write more than |
| 23 | +/// [`PAGE_SIZE`] - 1 bytes. |
| 24 | +/// |
| 25 | +/// [`PAGE_SIZE`]: `bindings::PAGE_SIZE` |
| 26 | +pub trait ModuleParam: Sized { |
| 27 | + /// The [`ModuleParam`] will be used by the kernel module through this type. |
| 28 | + /// |
| 29 | + /// This may differ from `Self` if, for example, `Self` needs to track |
| 30 | + /// ownership without exposing it or allocate extra space for other possible |
| 31 | + /// parameter values. |
| 32 | + // This is required to support string parameters in the future. |
| 33 | + type Value: ?Sized; |
| 34 | + |
| 35 | + /// Parse a parameter argument into the parameter value. |
| 36 | + /// |
| 37 | + /// `Err(_)` should be returned when parsing of the argument fails. |
| 38 | + /// |
| 39 | + /// Parameters passed at boot time will be set before [`kmalloc`] is |
| 40 | + /// available (even if the module is loaded at a later time). However, in |
| 41 | + /// this case, the argument buffer will be valid for the entire lifetime of |
| 42 | + /// the kernel. So implementations of this method which need to allocate |
| 43 | + /// should first check that the allocator is available (with |
| 44 | + /// [`crate::bindings::slab_is_available`]) and when it is not available |
| 45 | + /// provide an alternative implementation which doesn't allocate. In cases |
| 46 | + /// where the allocator is not available it is safe to save references to |
| 47 | + /// `arg` in `Self`, but in other cases a copy should be made. |
| 48 | + /// |
| 49 | + /// [`kmalloc`]: srctree/include/linux/slab.h |
| 50 | + fn try_from_param_arg(arg: &'static [u8]) -> Result<Self>; |
| 51 | +} |
| 52 | + |
| 53 | +/// Set the module parameter from a string. |
| 54 | +/// |
| 55 | +/// Used to set the parameter value at kernel initialization, when loading |
| 56 | +/// the module or when set through `sysfs`. |
| 57 | +/// |
| 58 | +/// `param.arg` is a pointer to `*mut T` as set up by the [`module!`] |
| 59 | +/// macro. |
| 60 | +/// |
| 61 | +/// See `struct kernel_param_ops.set`. |
| 62 | +/// |
| 63 | +/// # Safety |
| 64 | +/// |
| 65 | +/// If `val` is non-null then it must point to a valid null-terminated |
| 66 | +/// string. The `arg` field of `param` must be an instance of `T`. |
| 67 | +/// |
| 68 | +/// # Invariants |
| 69 | +/// |
| 70 | +/// Currently, we only support read-only parameters that are not readable |
| 71 | +/// from `sysfs`. Thus, this function is only called at kernel |
| 72 | +/// initialization time, or at module load time, and we have exclusive |
| 73 | +/// access to the parameter for the duration of the function. |
| 74 | +/// |
| 75 | +/// [`module!`]: macros::module |
| 76 | +unsafe extern "C" fn set_param<T>( |
| 77 | + val: *const kernel::ffi::c_char, |
| 78 | + param: *const crate::bindings::kernel_param, |
| 79 | +) -> core::ffi::c_int |
| 80 | +where |
| 81 | + T: ModuleParam, |
| 82 | +{ |
| 83 | + // NOTE: If we start supporting arguments without values, val _is_ allowed |
| 84 | + // to be null here. |
| 85 | + if val.is_null() { |
| 86 | + // TODO: Use pr_warn_once available. |
| 87 | + crate::pr_warn!("Null pointer passed to `module_param::set_param`"); |
| 88 | + return crate::error::code::EINVAL.to_errno(); |
| 89 | + } |
| 90 | + |
| 91 | + // SAFETY: By function safety requirement, val is non-null and |
| 92 | + // null-terminated. By C API contract, `val` is live and valid for reads |
| 93 | + // for the duration of this function. |
| 94 | + let arg = unsafe { CStr::from_char_ptr(val).as_bytes() }; |
| 95 | + |
| 96 | + crate::error::from_result(|| { |
| 97 | + let new_value = T::try_from_param_arg(arg)?; |
| 98 | + |
| 99 | + // SAFETY: `param` is guaranteed to be valid by C API contract |
| 100 | + // and `arg` is guaranteed to point to an instance of `T`. |
| 101 | + let old_value = unsafe { (*param).__bindgen_anon_1.arg as *mut T }; |
| 102 | + |
| 103 | + // SAFETY: `old_value` is valid for writes, as we have exclusive |
| 104 | + // access. `old_value` is pointing to an initialized static, and |
| 105 | + // so it is properly initialized. |
| 106 | + unsafe { core::ptr::replace(old_value, new_value) }; |
| 107 | + Ok(0) |
| 108 | + }) |
| 109 | +} |
| 110 | + |
| 111 | +/// Drop the parameter. |
| 112 | +/// |
| 113 | +/// Called when unloading a module. |
| 114 | +/// |
| 115 | +/// # Safety |
| 116 | +/// |
| 117 | +/// The `arg` field of `param` must be an initialized instance of `T`. |
| 118 | +unsafe extern "C" fn free<T>(arg: *mut core::ffi::c_void) |
| 119 | +where |
| 120 | + T: ModuleParam, |
| 121 | +{ |
| 122 | + // SAFETY: By function safety requirement, `arg` is an initialized |
| 123 | + // instance of `T`. By C API contract, `arg` will not be used after |
| 124 | + // this function returns. |
| 125 | + unsafe { core::ptr::drop_in_place(arg as *mut T) }; |
| 126 | +} |
| 127 | + |
| 128 | +macro_rules! impl_int_module_param { |
| 129 | + ($ty:ident) => { |
| 130 | + impl ModuleParam for $ty { |
| 131 | + type Value = $ty; |
| 132 | + |
| 133 | + fn try_from_param_arg(arg: &'static [u8]) -> Result<Self> { |
| 134 | + let bstr = BStr::from_bytes(arg); |
| 135 | + <$ty as crate::str::parse_int::ParseInt>::from_str(bstr) |
| 136 | + } |
| 137 | + } |
| 138 | + }; |
| 139 | +} |
| 140 | + |
| 141 | +impl_int_module_param!(i8); |
| 142 | +impl_int_module_param!(u8); |
| 143 | +impl_int_module_param!(i16); |
| 144 | +impl_int_module_param!(u16); |
| 145 | +impl_int_module_param!(i32); |
| 146 | +impl_int_module_param!(u32); |
| 147 | +impl_int_module_param!(i64); |
| 148 | +impl_int_module_param!(u64); |
| 149 | +impl_int_module_param!(isize); |
| 150 | +impl_int_module_param!(usize); |
| 151 | + |
| 152 | +/// A wrapper for kernel parameters. |
| 153 | +/// |
| 154 | +/// This type is instantiated by the [`module!`] macro when module parameters are |
| 155 | +/// defined. You should never need to instantiate this type directly. |
| 156 | +#[repr(transparent)] |
| 157 | +pub struct ModuleParamAccess<T> { |
| 158 | + data: core::cell::UnsafeCell<T>, |
| 159 | +} |
| 160 | + |
| 161 | +// SAFETY: We only create shared references to the contents of this container, |
| 162 | +// so if `T` is `Sync`, so is `ModuleParamAccess`. |
| 163 | +unsafe impl<T: Sync> Sync for ModuleParamAccess<T> {} |
| 164 | + |
| 165 | +impl<T> ModuleParamAccess<T> { |
| 166 | + #[doc(hidden)] |
| 167 | + pub const fn new(value: T) -> Self { |
| 168 | + Self { |
| 169 | + data: core::cell::UnsafeCell::new(value), |
| 170 | + } |
| 171 | + } |
| 172 | + |
| 173 | + /// Get a shared reference to the parameter value. |
| 174 | + // Note: When sysfs access to parameters are enabled, we have to pass in a |
| 175 | + // held lock guard here. |
| 176 | + pub fn get(&self) -> &T { |
| 177 | + // SAFETY: As we only support read only parameters with no sysfs |
| 178 | + // exposure, the kernel will not touch the parameter data after module |
| 179 | + // initialization. |
| 180 | + unsafe { &*self.data.get() } |
| 181 | + } |
| 182 | + |
| 183 | + /// Get a mutable pointer to the parameter value. |
| 184 | + pub const fn as_mut_ptr(&self) -> *mut T { |
| 185 | + self.data.get() |
| 186 | + } |
| 187 | +} |
| 188 | + |
| 189 | +#[doc(hidden)] |
| 190 | +#[macro_export] |
| 191 | +/// Generate a static [`kernel_param_ops`](srctree/include/linux/moduleparam.h) struct. |
| 192 | +/// |
| 193 | +/// # Examples |
| 194 | +/// |
| 195 | +/// ```ignore |
| 196 | +/// make_param_ops!( |
| 197 | +/// /// Documentation for new param ops. |
| 198 | +/// PARAM_OPS_MYTYPE, // Name for the static. |
| 199 | +/// MyType // A type which implements [`ModuleParam`]. |
| 200 | +/// ); |
| 201 | +/// ``` |
| 202 | +macro_rules! make_param_ops { |
| 203 | + ($ops:ident, $ty:ty) => { |
| 204 | + /// |
| 205 | + /// Static [`kernel_param_ops`](srctree/include/linux/moduleparam.h) |
| 206 | + /// struct generated by `make_param_ops` |
| 207 | + #[doc = concat!("for [`", stringify!($ty), "`].")] |
| 208 | + pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops { |
| 209 | + flags: 0, |
| 210 | + set: Some(set_param::<$ty>), |
| 211 | + get: None, |
| 212 | + free: Some(free::<$ty>), |
| 213 | + }; |
| 214 | + }; |
| 215 | +} |
| 216 | + |
| 217 | +make_param_ops!(PARAM_OPS_I8, i8); |
| 218 | +make_param_ops!(PARAM_OPS_U8, u8); |
| 219 | +make_param_ops!(PARAM_OPS_I16, i16); |
| 220 | +make_param_ops!(PARAM_OPS_U16, u16); |
| 221 | +make_param_ops!(PARAM_OPS_I32, i32); |
| 222 | +make_param_ops!(PARAM_OPS_U32, u32); |
| 223 | +make_param_ops!(PARAM_OPS_I64, i64); |
| 224 | +make_param_ops!(PARAM_OPS_U64, u64); |
| 225 | +make_param_ops!(PARAM_OPS_ISIZE, isize); |
| 226 | +make_param_ops!(PARAM_OPS_USIZE, usize); |
0 commit comments