Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'modules-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/modules/linux

Pull module updates from Daniel Gomez:
"Rust module parameter support:

- Add Rust module parameter support, enabling Rust kernel modules to
declare and use module parameters. The rust_minimal sample module
demonstrates this, and the rust null block driver will be the first
to use it in the next cycle. This also adds the Rust module files
under the modules subsystem as agreed between the Rust and modules
maintainers.

Hardening:

- Add compile-time check for embedded NUL characters in MODULE_*()
macros. This module metadata was once used (and maybe still) to
bypass license enforcement (LWN article from 2003):

https://lwn.net/Articles/82305/ [1]

MAINTAINERS:

- Add Aaron Tomlin as reviewer for the Modules subsystem"

* tag 'modules-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/modules/linux:
MAINTAINERS: Add myself as reviewer for module support
module: Add compile-time check for embedded NUL characters
media: radio: si470x: Fix DRIVER_AUTHOR macro definition
media: dvb-usb-v2: lmedm04: Fix firmware macro definitions
modules: add rust modules files to MAINTAINERS
rust: samples: add a module parameter to the rust_minimal sample
rust: module: update the module macro with module parameter support
rust: module: use a reference in macros::module::module
rust: introduce module_param module
rust: str: add radix prefixed integer parsing functions
rust: sync: add `SetOnce`

+717 -27
+3
MAINTAINERS
··· 17522 17522 M: Petr Pavlu <petr.pavlu@suse.com> 17523 17523 M: Daniel Gomez <da.gomez@kernel.org> 17524 17524 R: Sami Tolvanen <samitolvanen@google.com> 17525 + R: Aaron Tomlin <atomlin@atomlin.com> 17525 17526 L: linux-modules@vger.kernel.org 17526 17527 L: linux-kernel@vger.kernel.org 17527 17528 S: Maintained ··· 17532 17531 F: kernel/module/ 17533 17532 F: lib/test_kmod.c 17534 17533 F: lib/tests/module/ 17534 + F: rust/kernel/module_param.rs 17535 + F: rust/macros/module.rs 17535 17536 F: scripts/module* 17536 17537 F: tools/testing/selftests/kmod/ 17537 17538 F: tools/testing/selftests/module/
+1 -1
drivers/media/radio/si470x/radio-si470x-i2c.c
··· 10 10 11 11 12 12 /* driver definitions */ 13 - #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>"; 13 + #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>" 14 14 #define DRIVER_CARD "Silicon Labs Si470x FM Radio" 15 15 #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" 16 16 #define DRIVER_VERSION "1.0.2"
+6 -6
drivers/media/usb/dvb-usb-v2/lmedm04.c
··· 70 70 #include "ts2020.h" 71 71 72 72 73 - #define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw"; 74 - #define LME2510_C_LG "dvb-usb-lme2510c-lg.fw"; 75 - #define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw"; 76 - #define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw"; 77 - #define LME2510_LG "dvb-usb-lme2510-lg.fw"; 78 - #define LME2510_S0194 "dvb-usb-lme2510-s0194.fw"; 73 + #define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw" 74 + #define LME2510_C_LG "dvb-usb-lme2510c-lg.fw" 75 + #define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw" 76 + #define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw" 77 + #define LME2510_LG "dvb-usb-lme2510-lg.fw" 78 + #define LME2510_S0194 "dvb-usb-lme2510-s0194.fw" 79 79 80 80 /* debug */ 81 81 static int dvb_usb_lme2510_debug;
+3
include/linux/moduleparam.h
··· 26 26 27 27 /* Generic info of form tag = "info" */ 28 28 #define MODULE_INFO(tag, info) \ 29 + static_assert( \ 30 + sizeof(info) - 1 == __builtin_strlen(info), \ 31 + "MODULE_INFO(" #tag ", ...) contains embedded NUL byte"); \ 29 32 static const char __UNIQUE_ID(modinfo)[] \ 30 33 __used __section(".modinfo") __aligned(1) \ 31 34 = __MODULE_INFO_PREFIX __stringify(tag) "=" info
+1
rust/kernel/lib.rs
··· 112 112 pub mod maple_tree; 113 113 pub mod miscdevice; 114 114 pub mod mm; 115 + pub mod module_param; 115 116 #[cfg(CONFIG_NET)] 116 117 pub mod net; 117 118 pub mod num;
+182
rust/kernel/module_param.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Support 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 + use bindings; 10 + use kernel::sync::SetOnce; 11 + 12 + /// Newtype to make `bindings::kernel_param` [`Sync`]. 13 + #[repr(transparent)] 14 + #[doc(hidden)] 15 + pub struct KernelParam(bindings::kernel_param); 16 + 17 + impl KernelParam { 18 + #[doc(hidden)] 19 + pub const fn new(val: bindings::kernel_param) -> Self { 20 + Self(val) 21 + } 22 + } 23 + 24 + // SAFETY: C kernel handles serializing access to this type. We never access it 25 + // from Rust module. 26 + unsafe impl Sync for KernelParam {} 27 + 28 + /// Types that can be used for module parameters. 29 + // NOTE: This trait is `Copy` because drop could produce unsoundness during teardown. 30 + pub trait ModuleParam: Sized + Copy { 31 + /// Parse a parameter argument into the parameter value. 32 + fn try_from_param_arg(arg: &BStr) -> Result<Self>; 33 + } 34 + 35 + /// Set the module parameter from a string. 36 + /// 37 + /// Used to set the parameter value at kernel initialization, when loading 38 + /// the module or when set through `sysfs`. 39 + /// 40 + /// See `struct kernel_param_ops.set`. 41 + /// 42 + /// # Safety 43 + /// 44 + /// - If `val` is non-null then it must point to a valid null-terminated string that must be valid 45 + /// for reads for the duration of the call. 46 + /// - `param` must be a pointer to a `bindings::kernel_param` initialized by the rust module macro. 47 + /// The pointee must be valid for reads for the duration of the call. 48 + /// 49 + /// # Note 50 + /// 51 + /// - The safety requirements are satisfied by C API contract when this function is invoked by the 52 + /// module subsystem C code. 53 + /// - Currently, we only support read-only parameters that are not readable from `sysfs`. Thus, this 54 + /// function is only called at kernel initialization time, or at module load time, and we have 55 + /// exclusive access to the parameter for the duration of the function. 56 + /// 57 + /// [`module!`]: macros::module 58 + unsafe extern "C" fn set_param<T>(val: *const c_char, param: *const bindings::kernel_param) -> c_int 59 + where 60 + T: ModuleParam, 61 + { 62 + // NOTE: If we start supporting arguments without values, val _is_ allowed 63 + // to be null here. 64 + if val.is_null() { 65 + // TODO: Use pr_warn_once available. 66 + crate::pr_warn!("Null pointer passed to `module_param::set_param`"); 67 + return EINVAL.to_errno(); 68 + } 69 + 70 + // SAFETY: By function safety requirement, val is non-null, null-terminated 71 + // and valid for reads for the duration of this function. 72 + let arg = unsafe { CStr::from_char_ptr(val) }; 73 + let arg: &BStr = arg.as_ref(); 74 + 75 + crate::error::from_result(|| { 76 + let new_value = T::try_from_param_arg(arg)?; 77 + 78 + // SAFETY: By function safety requirements, this access is safe. 79 + let container = unsafe { &*((*param).__bindgen_anon_1.arg.cast::<SetOnce<T>>()) }; 80 + 81 + container 82 + .populate(new_value) 83 + .then_some(0) 84 + .ok_or(kernel::error::code::EEXIST) 85 + }) 86 + } 87 + 88 + macro_rules! impl_int_module_param { 89 + ($ty:ident) => { 90 + impl ModuleParam for $ty { 91 + fn try_from_param_arg(arg: &BStr) -> Result<Self> { 92 + <$ty as crate::str::parse_int::ParseInt>::from_str(arg) 93 + } 94 + } 95 + }; 96 + } 97 + 98 + impl_int_module_param!(i8); 99 + impl_int_module_param!(u8); 100 + impl_int_module_param!(i16); 101 + impl_int_module_param!(u16); 102 + impl_int_module_param!(i32); 103 + impl_int_module_param!(u32); 104 + impl_int_module_param!(i64); 105 + impl_int_module_param!(u64); 106 + impl_int_module_param!(isize); 107 + impl_int_module_param!(usize); 108 + 109 + /// A wrapper for kernel parameters. 110 + /// 111 + /// This type is instantiated by the [`module!`] macro when module parameters are 112 + /// defined. You should never need to instantiate this type directly. 113 + /// 114 + /// Note: This type is `pub` because it is used by module crates to access 115 + /// parameter values. 116 + pub struct ModuleParamAccess<T> { 117 + value: SetOnce<T>, 118 + default: T, 119 + } 120 + 121 + // SAFETY: We only create shared references to the contents of this container, 122 + // so if `T` is `Sync`, so is `ModuleParamAccess`. 123 + unsafe impl<T: Sync> Sync for ModuleParamAccess<T> {} 124 + 125 + impl<T> ModuleParamAccess<T> { 126 + #[doc(hidden)] 127 + pub const fn new(default: T) -> Self { 128 + Self { 129 + value: SetOnce::new(), 130 + default, 131 + } 132 + } 133 + 134 + /// Get a shared reference to the parameter value. 135 + // Note: When sysfs access to parameters are enabled, we have to pass in a 136 + // held lock guard here. 137 + pub fn value(&self) -> &T { 138 + self.value.as_ref().unwrap_or(&self.default) 139 + } 140 + 141 + /// Get a mutable pointer to `self`. 142 + /// 143 + /// NOTE: In most cases it is not safe deref the returned pointer. 144 + pub const fn as_void_ptr(&self) -> *mut c_void { 145 + core::ptr::from_ref(self).cast_mut().cast() 146 + } 147 + } 148 + 149 + #[doc(hidden)] 150 + /// Generate a static [`kernel_param_ops`](srctree/include/linux/moduleparam.h) struct. 151 + /// 152 + /// # Examples 153 + /// 154 + /// ```ignore 155 + /// make_param_ops!( 156 + /// /// Documentation for new param ops. 157 + /// PARAM_OPS_MYTYPE, // Name for the static. 158 + /// MyType // A type which implements [`ModuleParam`]. 159 + /// ); 160 + /// ``` 161 + macro_rules! make_param_ops { 162 + ($ops:ident, $ty:ty) => { 163 + #[doc(hidden)] 164 + pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops { 165 + flags: 0, 166 + set: Some(set_param::<$ty>), 167 + get: None, 168 + free: None, 169 + }; 170 + }; 171 + } 172 + 173 + make_param_ops!(PARAM_OPS_I8, i8); 174 + make_param_ops!(PARAM_OPS_U8, u8); 175 + make_param_ops!(PARAM_OPS_I16, i16); 176 + make_param_ops!(PARAM_OPS_U16, u16); 177 + make_param_ops!(PARAM_OPS_I32, i32); 178 + make_param_ops!(PARAM_OPS_U32, u32); 179 + make_param_ops!(PARAM_OPS_I64, i64); 180 + make_param_ops!(PARAM_OPS_U64, u64); 181 + make_param_ops!(PARAM_OPS_ISIZE, isize); 182 + make_param_ops!(PARAM_OPS_USIZE, usize);
+2
rust/kernel/str.rs
··· 15 15 16 16 pub use crate::prelude::CStr; 17 17 18 + pub mod parse_int; 19 + 18 20 /// Byte string without UTF-8 validity guarantee. 19 21 #[repr(transparent)] 20 22 pub struct BStr([u8]);
+148
rust/kernel/str/parse_int.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Integer parsing functions. 4 + //! 5 + //! Integer parsing functions for parsing signed and unsigned integers 6 + //! potentially prefixed with `0x`, `0o`, or `0b`. 7 + 8 + use crate::prelude::*; 9 + use crate::str::BStr; 10 + use core::ops::Deref; 11 + 12 + // Make `FromStrRadix` a public type with a private name. This seals 13 + // `ParseInt`, that is, prevents downstream users from implementing the 14 + // trait. 15 + mod private { 16 + use crate::prelude::*; 17 + use crate::str::BStr; 18 + 19 + /// Trait that allows parsing a [`&BStr`] to an integer with a radix. 20 + pub trait FromStrRadix: Sized { 21 + /// Parse `src` to [`Self`] using radix `radix`. 22 + fn from_str_radix(src: &BStr, radix: u32) -> Result<Self>; 23 + 24 + /// Tries to convert `value` into [`Self`] and negates the resulting value. 25 + fn from_u64_negated(value: u64) -> Result<Self>; 26 + } 27 + } 28 + 29 + /// Extract the radix from an integer literal optionally prefixed with 30 + /// one of `0x`, `0X`, `0o`, `0O`, `0b`, `0B`, `0`. 31 + fn strip_radix(src: &BStr) -> (u32, &BStr) { 32 + match src.deref() { 33 + [b'0', b'x' | b'X', rest @ ..] => (16, rest.as_ref()), 34 + [b'0', b'o' | b'O', rest @ ..] => (8, rest.as_ref()), 35 + [b'0', b'b' | b'B', rest @ ..] => (2, rest.as_ref()), 36 + // NOTE: We are including the leading zero to be able to parse 37 + // literal `0` here. If we removed it as a radix prefix, we would 38 + // not be able to parse `0`. 39 + [b'0', ..] => (8, src), 40 + _ => (10, src), 41 + } 42 + } 43 + 44 + /// Trait for parsing string representations of integers. 45 + /// 46 + /// Strings beginning with `0x`, `0o`, or `0b` are parsed as hex, octal, or 47 + /// binary respectively. Strings beginning with `0` otherwise are parsed as 48 + /// octal. Anything else is parsed as decimal. A leading `+` or `-` is also 49 + /// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be 50 + /// successfully parsed. 51 + /// 52 + /// [`kstrtol()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtol 53 + /// [`kstrtoul()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtoul 54 + /// 55 + /// # Examples 56 + /// 57 + /// ``` 58 + /// # use kernel::str::parse_int::ParseInt; 59 + /// # use kernel::b_str; 60 + /// 61 + /// assert_eq!(Ok(0u8), u8::from_str(b_str!("0"))); 62 + /// 63 + /// assert_eq!(Ok(0xa2u8), u8::from_str(b_str!("0xa2"))); 64 + /// assert_eq!(Ok(-0xa2i32), i32::from_str(b_str!("-0xa2"))); 65 + /// 66 + /// assert_eq!(Ok(-0o57i8), i8::from_str(b_str!("-0o57"))); 67 + /// assert_eq!(Ok(0o57i8), i8::from_str(b_str!("057"))); 68 + /// 69 + /// assert_eq!(Ok(0b1001i16), i16::from_str(b_str!("0b1001"))); 70 + /// assert_eq!(Ok(-0b1001i16), i16::from_str(b_str!("-0b1001"))); 71 + /// 72 + /// assert_eq!(Ok(127i8), i8::from_str(b_str!("127"))); 73 + /// assert!(i8::from_str(b_str!("128")).is_err()); 74 + /// assert_eq!(Ok(-128i8), i8::from_str(b_str!("-128"))); 75 + /// assert!(i8::from_str(b_str!("-129")).is_err()); 76 + /// assert_eq!(Ok(255u8), u8::from_str(b_str!("255"))); 77 + /// assert!(u8::from_str(b_str!("256")).is_err()); 78 + /// ``` 79 + pub trait ParseInt: private::FromStrRadix + TryFrom<u64> { 80 + /// Parse a string according to the description in [`Self`]. 81 + fn from_str(src: &BStr) -> Result<Self> { 82 + match src.deref() { 83 + [b'-', rest @ ..] => { 84 + let (radix, digits) = strip_radix(rest.as_ref()); 85 + // 2's complement values range from -2^(b-1) to 2^(b-1)-1. 86 + // So if we want to parse negative numbers as positive and 87 + // later multiply by -1, we have to parse into a larger 88 + // integer. We choose `u64` as sufficiently large. 89 + // 90 + // NOTE: 128 bit integers are not available on all 91 + // platforms, hence the choice of 64 bits. 92 + let val = 93 + u64::from_str_radix(core::str::from_utf8(digits).map_err(|_| EINVAL)?, radix) 94 + .map_err(|_| EINVAL)?; 95 + Self::from_u64_negated(val) 96 + } 97 + _ => { 98 + let (radix, digits) = strip_radix(src); 99 + Self::from_str_radix(digits, radix).map_err(|_| EINVAL) 100 + } 101 + } 102 + } 103 + } 104 + 105 + macro_rules! impl_parse_int { 106 + ($($ty:ty),*) => { 107 + $( 108 + impl private::FromStrRadix for $ty { 109 + fn from_str_radix(src: &BStr, radix: u32) -> Result<Self> { 110 + <$ty>::from_str_radix(core::str::from_utf8(src).map_err(|_| EINVAL)?, radix) 111 + .map_err(|_| EINVAL) 112 + } 113 + 114 + fn from_u64_negated(value: u64) -> Result<Self> { 115 + const ABS_MIN: u64 = { 116 + #[allow(unused_comparisons)] 117 + if <$ty>::MIN < 0 { 118 + 1u64 << (<$ty>::BITS - 1) 119 + } else { 120 + 0 121 + } 122 + }; 123 + 124 + if value > ABS_MIN { 125 + return Err(EINVAL); 126 + } 127 + 128 + if value == ABS_MIN { 129 + return Ok(<$ty>::MIN); 130 + } 131 + 132 + // SAFETY: The above checks guarantee that `value` fits into `Self`: 133 + // - if `Self` is unsigned, then `ABS_MIN == 0` and thus we have returned above 134 + // (either `EINVAL` or `MIN`). 135 + // - if `Self` is signed, then we have that `0 <= value < ABS_MIN`. And since 136 + // `ABS_MIN - 1` fits into `Self` by construction, `value` also does. 137 + let value: Self = unsafe { value.try_into().unwrap_unchecked() }; 138 + 139 + Ok((!value).wrapping_add(1)) 140 + } 141 + } 142 + 143 + impl ParseInt for $ty {} 144 + )* 145 + }; 146 + } 147 + 148 + impl_parse_int![i8, u8, i16, u16, i32, u32, i64, u64, isize, usize];
+2
rust/kernel/sync.rs
··· 20 20 pub mod poll; 21 21 pub mod rcu; 22 22 mod refcount; 23 + mod set_once; 23 24 24 25 pub use arc::{Arc, ArcBorrow, UniqueArc}; 25 26 pub use completion::Completion; ··· 30 29 pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard}; 31 30 pub use locked_by::LockedBy; 32 31 pub use refcount::Refcount; 32 + pub use set_once::SetOnce; 33 33 34 34 /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. 35 35 #[repr(transparent)]
+125
rust/kernel/sync/set_once.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! A container that can be initialized at most once. 4 + 5 + use super::atomic::{ 6 + ordering::{Acquire, Relaxed, Release}, 7 + Atomic, 8 + }; 9 + use core::{cell::UnsafeCell, mem::MaybeUninit}; 10 + 11 + /// A container that can be populated at most once. Thread safe. 12 + /// 13 + /// Once the a [`SetOnce`] is populated, it remains populated by the same object for the 14 + /// lifetime `Self`. 15 + /// 16 + /// # Invariants 17 + /// 18 + /// - `init` may only increase in value. 19 + /// - `init` may only assume values in the range `0..=2`. 20 + /// - `init == 0` if and only if `value` is uninitialized. 21 + /// - `init == 1` if and only if there is exactly one thread with exclusive 22 + /// access to `self.value`. 23 + /// - `init == 2` if and only if `value` is initialized and valid for shared 24 + /// access. 25 + /// 26 + /// # Example 27 + /// 28 + /// ``` 29 + /// # use kernel::sync::SetOnce; 30 + /// let value = SetOnce::new(); 31 + /// assert_eq!(None, value.as_ref()); 32 + /// 33 + /// let status = value.populate(42u8); 34 + /// assert_eq!(true, status); 35 + /// assert_eq!(Some(&42u8), value.as_ref()); 36 + /// assert_eq!(Some(42u8), value.copy()); 37 + /// 38 + /// let status = value.populate(101u8); 39 + /// assert_eq!(false, status); 40 + /// assert_eq!(Some(&42u8), value.as_ref()); 41 + /// assert_eq!(Some(42u8), value.copy()); 42 + /// ``` 43 + pub struct SetOnce<T> { 44 + init: Atomic<u32>, 45 + value: UnsafeCell<MaybeUninit<T>>, 46 + } 47 + 48 + impl<T> Default for SetOnce<T> { 49 + fn default() -> Self { 50 + Self::new() 51 + } 52 + } 53 + 54 + impl<T> SetOnce<T> { 55 + /// Create a new [`SetOnce`]. 56 + /// 57 + /// The returned instance will be empty. 58 + pub const fn new() -> Self { 59 + // INVARIANT: The container is empty and we initialize `init` to `0`. 60 + Self { 61 + value: UnsafeCell::new(MaybeUninit::uninit()), 62 + init: Atomic::new(0), 63 + } 64 + } 65 + 66 + /// Get a reference to the contained object. 67 + /// 68 + /// Returns [`None`] if this [`SetOnce`] is empty. 69 + pub fn as_ref(&self) -> Option<&T> { 70 + if self.init.load(Acquire) == 2 { 71 + // SAFETY: By the type invariants of `Self`, `self.init == 2` means that `self.value` 72 + // is initialized and valid for shared access. 73 + Some(unsafe { &*self.value.get().cast() }) 74 + } else { 75 + None 76 + } 77 + } 78 + 79 + /// Populate the [`SetOnce`]. 80 + /// 81 + /// Returns `true` if the [`SetOnce`] was successfully populated. 82 + pub fn populate(&self, value: T) -> bool { 83 + // INVARIANT: If the swap succeeds: 84 + // - We increase `init`. 85 + // - We write the valid value `1` to `init`. 86 + // - Only one thread can succeed in this write, so we have exclusive access after the 87 + // write. 88 + if let Ok(0) = self.init.cmpxchg(0, 1, Relaxed) { 89 + // SAFETY: By the type invariants of `Self`, the fact that we succeeded in writing `1` 90 + // to `self.init` means we obtained exclusive access to `self.value`. 91 + unsafe { core::ptr::write(self.value.get().cast(), value) }; 92 + // INVARIANT: 93 + // - We increase `init`. 94 + // - We write the valid value `2` to `init`. 95 + // - We release our exclusive access to `self.value` and it is now valid for shared 96 + // access. 97 + self.init.store(2, Release); 98 + true 99 + } else { 100 + false 101 + } 102 + } 103 + 104 + /// Get a copy of the contained object. 105 + /// 106 + /// Returns [`None`] if the [`SetOnce`] is empty. 107 + pub fn copy(&self) -> Option<T> 108 + where 109 + T: Copy, 110 + { 111 + self.as_ref().copied() 112 + } 113 + } 114 + 115 + impl<T> Drop for SetOnce<T> { 116 + fn drop(&mut self) { 117 + if *self.init.get_mut() == 2 { 118 + let value = self.value.get_mut(); 119 + // SAFETY: By the type invariants of `Self`, `self.init == 2` means that `self.value` 120 + // contains a valid value. We have exclusive access, as we hold a `mut` reference to 121 + // `self`. 122 + unsafe { value.assume_init_drop() }; 123 + } 124 + } 125 + }
+25
rust/macros/helpers.rs
··· 10 10 } 11 11 } 12 12 13 + pub(crate) fn try_sign(it: &mut token_stream::IntoIter) -> Option<char> { 14 + let peek = it.clone().next(); 15 + match peek { 16 + Some(TokenTree::Punct(punct)) if punct.as_char() == '-' => { 17 + let _ = it.next(); 18 + Some(punct.as_char()) 19 + } 20 + _ => None, 21 + } 22 + } 23 + 13 24 pub(crate) fn try_literal(it: &mut token_stream::IntoIter) -> Option<String> { 14 25 if let Some(TokenTree::Literal(literal)) = it.next() { 15 26 Some(literal.to_string()) ··· 113 102 { 114 103 proc_macro::Span::call_site().file() 115 104 } 105 + } 106 + 107 + /// Parse a token stream of the form `expected_name: "value",` and return the 108 + /// string in the position of "value". 109 + /// 110 + /// # Panics 111 + /// 112 + /// - On parse error. 113 + pub(crate) fn expect_string_field(it: &mut token_stream::IntoIter, expected_name: &str) -> String { 114 + assert_eq!(expect_ident(it), expected_name); 115 + assert_eq!(expect_punct(it), ':'); 116 + let string = expect_string(it); 117 + assert_eq!(expect_punct(it), ','); 118 + string 116 119 }
+31
rust/macros/lib.rs
··· 29 29 /// The `type` argument should be a type which implements the [`Module`] 30 30 /// trait. Also accepts various forms of kernel metadata. 31 31 /// 32 + /// The `params` field describe module parameters. Each entry has the form 33 + /// 34 + /// ```ignore 35 + /// parameter_name: type { 36 + /// default: default_value, 37 + /// description: "Description", 38 + /// } 39 + /// ``` 40 + /// 41 + /// `type` may be one of 42 + /// 43 + /// - [`i8`] 44 + /// - [`u8`] 45 + /// - [`i8`] 46 + /// - [`u8`] 47 + /// - [`i16`] 48 + /// - [`u16`] 49 + /// - [`i32`] 50 + /// - [`u32`] 51 + /// - [`i64`] 52 + /// - [`u64`] 53 + /// - [`isize`] 54 + /// - [`usize`] 55 + /// 32 56 /// C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h) 33 57 /// 34 58 /// [`Module`]: ../kernel/trait.Module.html ··· 69 45 /// description: "My very own kernel module!", 70 46 /// license: "GPL", 71 47 /// alias: ["alternate_module_name"], 48 + /// params: { 49 + /// my_parameter: i64 { 50 + /// default: 1, 51 + /// description: "This parameter has a default of 1", 52 + /// }, 53 + /// }, 72 54 /// } 73 55 /// 74 56 /// struct MyModule(i32); ··· 83 53 /// fn init(_module: &'static ThisModule) -> Result<Self> { 84 54 /// let foo: i32 = 42; 85 55 /// pr_info!("I contain: {}\n", foo); 56 + /// pr_info!("i32 param is: {}\n", module_parameters::my_parameter.read()); 86 57 /// Ok(Self(foo)) 87 58 /// } 88 59 /// }
+178 -20
rust/macros/module.rs
··· 26 26 module: &'a str, 27 27 counter: usize, 28 28 buffer: String, 29 + param_buffer: String, 29 30 } 30 31 31 32 impl<'a> ModInfoBuilder<'a> { ··· 35 34 module, 36 35 counter: 0, 37 36 buffer: String::new(), 37 + param_buffer: String::new(), 38 38 } 39 39 } 40 40 41 - fn emit_base(&mut self, field: &str, content: &str, builtin: bool) { 41 + fn emit_base(&mut self, field: &str, content: &str, builtin: bool, param: bool) { 42 42 let string = if builtin { 43 43 // Built-in modules prefix their modinfo strings by `module.`. 44 44 format!( ··· 53 51 format!("{field}={content}\0") 54 52 }; 55 53 54 + let buffer = if param { 55 + &mut self.param_buffer 56 + } else { 57 + &mut self.buffer 58 + }; 59 + 56 60 write!( 57 - &mut self.buffer, 61 + buffer, 58 62 " 59 63 {cfg} 60 64 #[doc(hidden)] ··· 83 75 self.counter += 1; 84 76 } 85 77 86 - fn emit_only_builtin(&mut self, field: &str, content: &str) { 87 - self.emit_base(field, content, true) 78 + fn emit_only_builtin(&mut self, field: &str, content: &str, param: bool) { 79 + self.emit_base(field, content, true, param) 88 80 } 89 81 90 - fn emit_only_loadable(&mut self, field: &str, content: &str) { 91 - self.emit_base(field, content, false) 82 + fn emit_only_loadable(&mut self, field: &str, content: &str, param: bool) { 83 + self.emit_base(field, content, false, param) 92 84 } 93 85 94 86 fn emit(&mut self, field: &str, content: &str) { 95 - self.emit_only_builtin(field, content); 96 - self.emit_only_loadable(field, content); 87 + self.emit_internal(field, content, false); 97 88 } 89 + 90 + fn emit_internal(&mut self, field: &str, content: &str, param: bool) { 91 + self.emit_only_builtin(field, content, param); 92 + self.emit_only_loadable(field, content, param); 93 + } 94 + 95 + fn emit_param(&mut self, field: &str, param: &str, content: &str) { 96 + let content = format!("{param}:{content}", param = param, content = content); 97 + self.emit_internal(field, &content, true); 98 + } 99 + 100 + fn emit_params(&mut self, info: &ModuleInfo) { 101 + let Some(params) = &info.params else { 102 + return; 103 + }; 104 + 105 + for param in params { 106 + let ops = param_ops_path(&param.ptype); 107 + 108 + // Note: The spelling of these fields is dictated by the user space 109 + // tool `modinfo`. 110 + self.emit_param("parmtype", &param.name, &param.ptype); 111 + self.emit_param("parm", &param.name, &param.description); 112 + 113 + write!( 114 + self.param_buffer, 115 + " 116 + pub(crate) static {param_name}: 117 + ::kernel::module_param::ModuleParamAccess<{param_type}> = 118 + ::kernel::module_param::ModuleParamAccess::new({param_default}); 119 + 120 + const _: () = {{ 121 + #[link_section = \"__param\"] 122 + #[used] 123 + static __{module_name}_{param_name}_struct: 124 + ::kernel::module_param::KernelParam = 125 + ::kernel::module_param::KernelParam::new( 126 + ::kernel::bindings::kernel_param {{ 127 + name: if ::core::cfg!(MODULE) {{ 128 + ::kernel::c_str!(\"{param_name}\").to_bytes_with_nul() 129 + }} else {{ 130 + ::kernel::c_str!(\"{module_name}.{param_name}\") 131 + .to_bytes_with_nul() 132 + }}.as_ptr(), 133 + // SAFETY: `__this_module` is constructed by the kernel at load 134 + // time and will not be freed until the module is unloaded. 135 + #[cfg(MODULE)] 136 + mod_: unsafe {{ 137 + core::ptr::from_ref(&::kernel::bindings::__this_module) 138 + .cast_mut() 139 + }}, 140 + #[cfg(not(MODULE))] 141 + mod_: ::core::ptr::null_mut(), 142 + ops: core::ptr::from_ref(&{ops}), 143 + perm: 0, // Will not appear in sysfs 144 + level: -1, 145 + flags: 0, 146 + __bindgen_anon_1: ::kernel::bindings::kernel_param__bindgen_ty_1 {{ 147 + arg: {param_name}.as_void_ptr() 148 + }}, 149 + }} 150 + ); 151 + }}; 152 + ", 153 + module_name = info.name, 154 + param_type = param.ptype, 155 + param_default = param.default, 156 + param_name = param.name, 157 + ops = ops, 158 + ) 159 + .unwrap(); 160 + } 161 + } 162 + } 163 + 164 + fn param_ops_path(param_type: &str) -> &'static str { 165 + match param_type { 166 + "i8" => "::kernel::module_param::PARAM_OPS_I8", 167 + "u8" => "::kernel::module_param::PARAM_OPS_U8", 168 + "i16" => "::kernel::module_param::PARAM_OPS_I16", 169 + "u16" => "::kernel::module_param::PARAM_OPS_U16", 170 + "i32" => "::kernel::module_param::PARAM_OPS_I32", 171 + "u32" => "::kernel::module_param::PARAM_OPS_U32", 172 + "i64" => "::kernel::module_param::PARAM_OPS_I64", 173 + "u64" => "::kernel::module_param::PARAM_OPS_U64", 174 + "isize" => "::kernel::module_param::PARAM_OPS_ISIZE", 175 + "usize" => "::kernel::module_param::PARAM_OPS_USIZE", 176 + t => panic!("Unsupported parameter type {}", t), 177 + } 178 + } 179 + 180 + fn expect_param_default(param_it: &mut token_stream::IntoIter) -> String { 181 + assert_eq!(expect_ident(param_it), "default"); 182 + assert_eq!(expect_punct(param_it), ':'); 183 + let sign = try_sign(param_it); 184 + let default = try_literal(param_it).expect("Expected default param value"); 185 + assert_eq!(expect_punct(param_it), ','); 186 + let mut value = sign.map(String::from).unwrap_or_default(); 187 + value.push_str(&default); 188 + value 98 189 } 99 190 100 191 #[derive(Debug, Default)] ··· 206 99 alias: Option<Vec<String>>, 207 100 firmware: Option<Vec<String>>, 208 101 imports_ns: Option<Vec<String>>, 102 + params: Option<Vec<Parameter>>, 103 + } 104 + 105 + #[derive(Debug)] 106 + struct Parameter { 107 + name: String, 108 + ptype: String, 109 + default: String, 110 + description: String, 111 + } 112 + 113 + fn expect_params(it: &mut token_stream::IntoIter) -> Vec<Parameter> { 114 + let params = expect_group(it); 115 + assert_eq!(params.delimiter(), Delimiter::Brace); 116 + let mut it = params.stream().into_iter(); 117 + let mut parsed = Vec::new(); 118 + 119 + loop { 120 + let param_name = match it.next() { 121 + Some(TokenTree::Ident(ident)) => ident.to_string(), 122 + Some(_) => panic!("Expected Ident or end"), 123 + None => break, 124 + }; 125 + 126 + assert_eq!(expect_punct(&mut it), ':'); 127 + let param_type = expect_ident(&mut it); 128 + let group = expect_group(&mut it); 129 + assert_eq!(group.delimiter(), Delimiter::Brace); 130 + assert_eq!(expect_punct(&mut it), ','); 131 + 132 + let mut param_it = group.stream().into_iter(); 133 + let param_default = expect_param_default(&mut param_it); 134 + let param_description = expect_string_field(&mut param_it, "description"); 135 + expect_end(&mut param_it); 136 + 137 + parsed.push(Parameter { 138 + name: param_name, 139 + ptype: param_type, 140 + default: param_default, 141 + description: param_description, 142 + }) 143 + } 144 + 145 + parsed 209 146 } 210 147 211 148 impl ModuleInfo { ··· 265 114 "alias", 266 115 "firmware", 267 116 "imports_ns", 117 + "params", 268 118 ]; 269 119 const REQUIRED_KEYS: &[&str] = &["type", "name", "license"]; 270 120 let mut seen_keys = Vec::new(); ··· 292 140 "alias" => info.alias = Some(expect_string_array(it)), 293 141 "firmware" => info.firmware = Some(expect_string_array(it)), 294 142 "imports_ns" => info.imports_ns = Some(expect_string_array(it)), 143 + "params" => info.params = Some(expect_params(it)), 295 144 _ => panic!("Unknown key \"{key}\". Valid keys are: {EXPECTED_KEYS:?}."), 296 145 } 297 146 ··· 332 179 // Rust does not allow hyphens in identifiers, use underscore instead. 333 180 let ident = info.name.replace('-', "_"); 334 181 let mut modinfo = ModInfoBuilder::new(ident.as_ref()); 335 - if let Some(authors) = info.authors { 182 + if let Some(authors) = &info.authors { 336 183 for author in authors { 337 - modinfo.emit("author", &author); 184 + modinfo.emit("author", author); 338 185 } 339 186 } 340 - if let Some(description) = info.description { 341 - modinfo.emit("description", &description); 187 + if let Some(description) = &info.description { 188 + modinfo.emit("description", description); 342 189 } 343 190 modinfo.emit("license", &info.license); 344 - if let Some(aliases) = info.alias { 191 + if let Some(aliases) = &info.alias { 345 192 for alias in aliases { 346 - modinfo.emit("alias", &alias); 193 + modinfo.emit("alias", alias); 347 194 } 348 195 } 349 - if let Some(firmware) = info.firmware { 196 + if let Some(firmware) = &info.firmware { 350 197 for fw in firmware { 351 - modinfo.emit("firmware", &fw); 198 + modinfo.emit("firmware", fw); 352 199 } 353 200 } 354 - if let Some(imports) = info.imports_ns { 201 + if let Some(imports) = &info.imports_ns { 355 202 for ns in imports { 356 - modinfo.emit("import_ns", &ns); 203 + modinfo.emit("import_ns", ns); 357 204 } 358 205 } 359 206 360 207 // Built-in modules also export the `file` modinfo string. 361 208 let file = 362 209 std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable"); 363 - modinfo.emit_only_builtin("file", &file); 210 + modinfo.emit_only_builtin("file", &file, false); 211 + 212 + modinfo.emit_params(&info); 364 213 365 214 format!( 366 215 " ··· 526 371 __MOD.assume_init_drop(); 527 372 }} 528 373 }} 529 - 530 374 {modinfo} 531 375 }} 376 + }} 377 + mod module_parameters {{ 378 + {params} 532 379 }} 533 380 ", 534 381 type_ = info.type_, 535 382 name = info.name, 536 383 ident = ident, 537 384 modinfo = modinfo.buffer, 385 + params = modinfo.param_buffer, 538 386 initcall_section = ".initcall6.init" 539 387 ) 540 388 .parse()
+10
samples/rust/rust_minimal.rs
··· 10 10 authors: ["Rust for Linux Contributors"], 11 11 description: "Rust minimal sample", 12 12 license: "GPL", 13 + params: { 14 + test_parameter: i64 { 15 + default: 1, 16 + description: "This parameter has a default of 1", 17 + }, 18 + }, 13 19 } 14 20 15 21 struct RustMinimal { ··· 26 20 fn init(_module: &'static ThisModule) -> Result<Self> { 27 21 pr_info!("Rust minimal sample (init)\n"); 28 22 pr_info!("Am I built-in? {}\n", !cfg!(MODULE)); 23 + pr_info!( 24 + "test_parameter: {}\n", 25 + *module_parameters::test_parameter.value() 26 + ); 29 27 30 28 let mut numbers = KVec::new(); 31 29 numbers.push(72, GFP_KERNEL)?;