Commit c84d574698ba for kernel

commit c84d574698bad2c02aad506dfe712f83cbe3b771
Merge: 416f99c3b16f 1ddac5cd7f27
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Sat Dec 6 08:27:07 2025 -0800

    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`

diff --cc rust/kernel/lib.rs
index 12c4f0c1cdaf,e81bbae91c83..6083dec1f190
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@@ -112,9 -107,9 +112,10 @@@ pub mod list
  pub mod maple_tree;
  pub mod miscdevice;
  pub mod mm;
+ pub mod module_param;
  #[cfg(CONFIG_NET)]
  pub mod net;
 +pub mod num;
  pub mod of;
  #[cfg(CONFIG_PM_OPP)]
  pub mod opp;
diff --cc rust/kernel/module_param.rs
index 000000000000,e7d5c930a467..6a8a7a875643
mode 000000,100644..100644
--- a/rust/kernel/module_param.rs
+++ b/rust/kernel/module_param.rs
@@@ -1,0 -1,181 +1,182 @@@
+ // SPDX-License-Identifier: GPL-2.0
+
+ //! Support for module parameters.
+ //!
+ //! C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h)
+
+ use crate::prelude::*;
+ use crate::str::BStr;
+ use bindings;
+ use kernel::sync::SetOnce;
+
+ /// Newtype to make `bindings::kernel_param` [`Sync`].
+ #[repr(transparent)]
+ #[doc(hidden)]
+ pub struct KernelParam(bindings::kernel_param);
+
+ impl KernelParam {
+     #[doc(hidden)]
+     pub const fn new(val: bindings::kernel_param) -> Self {
+         Self(val)
+     }
+ }
+
+ // SAFETY: C kernel handles serializing access to this type. We never access it
+ // from Rust module.
+ unsafe impl Sync for KernelParam {}
+
+ /// Types that can be used for module parameters.
+ // NOTE: This trait is `Copy` because drop could produce unsoundness during teardown.
+ pub trait ModuleParam: Sized + Copy {
+     /// Parse a parameter argument into the parameter value.
+     fn try_from_param_arg(arg: &BStr) -> Result<Self>;
+ }
+
+ /// Set the module parameter from a string.
+ ///
+ /// Used to set the parameter value at kernel initialization, when loading
+ /// the module or when set through `sysfs`.
+ ///
+ /// See `struct kernel_param_ops.set`.
+ ///
+ /// # Safety
+ ///
+ /// - If `val` is non-null then it must point to a valid null-terminated string that must be valid
+ ///   for reads for the duration of the call.
+ /// - `param` must be a pointer to a `bindings::kernel_param` initialized by the rust module macro.
+ ///   The pointee must be valid for reads for the duration of the call.
+ ///
+ /// # Note
+ ///
+ /// - The safety requirements are satisfied by C API contract when this function is invoked by the
+ ///   module subsystem C code.
+ /// - Currently, we only support read-only parameters that are not readable from `sysfs`. Thus, this
+ ///   function is only called at kernel initialization time, or at module load time, and we have
+ ///   exclusive access to the parameter for the duration of the function.
+ ///
+ /// [`module!`]: macros::module
+ unsafe extern "C" fn set_param<T>(val: *const c_char, param: *const bindings::kernel_param) -> c_int
+ where
+     T: ModuleParam,
+ {
+     // NOTE: If we start supporting arguments without values, val _is_ allowed
+     // to be null here.
+     if val.is_null() {
+         // TODO: Use pr_warn_once available.
+         crate::pr_warn!("Null pointer passed to `module_param::set_param`");
+         return EINVAL.to_errno();
+     }
+
+     // SAFETY: By function safety requirement, val is non-null, null-terminated
+     // and valid for reads for the duration of this function.
+     let arg = unsafe { CStr::from_char_ptr(val) };
++    let arg: &BStr = arg.as_ref();
+
+     crate::error::from_result(|| {
+         let new_value = T::try_from_param_arg(arg)?;
+
+         // SAFETY: By function safety requirements, this access is safe.
+         let container = unsafe { &*((*param).__bindgen_anon_1.arg.cast::<SetOnce<T>>()) };
+
+         container
+             .populate(new_value)
+             .then_some(0)
+             .ok_or(kernel::error::code::EEXIST)
+     })
+ }
+
+ macro_rules! impl_int_module_param {
+     ($ty:ident) => {
+         impl ModuleParam for $ty {
+             fn try_from_param_arg(arg: &BStr) -> Result<Self> {
+                 <$ty as crate::str::parse_int::ParseInt>::from_str(arg)
+             }
+         }
+     };
+ }
+
+ impl_int_module_param!(i8);
+ impl_int_module_param!(u8);
+ impl_int_module_param!(i16);
+ impl_int_module_param!(u16);
+ impl_int_module_param!(i32);
+ impl_int_module_param!(u32);
+ impl_int_module_param!(i64);
+ impl_int_module_param!(u64);
+ impl_int_module_param!(isize);
+ impl_int_module_param!(usize);
+
+ /// A wrapper for kernel parameters.
+ ///
+ /// This type is instantiated by the [`module!`] macro when module parameters are
+ /// defined. You should never need to instantiate this type directly.
+ ///
+ /// Note: This type is `pub` because it is used by module crates to access
+ /// parameter values.
+ pub struct ModuleParamAccess<T> {
+     value: SetOnce<T>,
+     default: T,
+ }
+
+ // SAFETY: We only create shared references to the contents of this container,
+ // so if `T` is `Sync`, so is `ModuleParamAccess`.
+ unsafe impl<T: Sync> Sync for ModuleParamAccess<T> {}
+
+ impl<T> ModuleParamAccess<T> {
+     #[doc(hidden)]
+     pub const fn new(default: T) -> Self {
+         Self {
+             value: SetOnce::new(),
+             default,
+         }
+     }
+
+     /// Get a shared reference to the parameter value.
+     // Note: When sysfs access to parameters are enabled, we have to pass in a
+     // held lock guard here.
+     pub fn value(&self) -> &T {
+         self.value.as_ref().unwrap_or(&self.default)
+     }
+
+     /// Get a mutable pointer to `self`.
+     ///
+     /// NOTE: In most cases it is not safe deref the returned pointer.
+     pub const fn as_void_ptr(&self) -> *mut c_void {
+         core::ptr::from_ref(self).cast_mut().cast()
+     }
+ }
+
+ #[doc(hidden)]
+ /// Generate a static [`kernel_param_ops`](srctree/include/linux/moduleparam.h) struct.
+ ///
+ /// # Examples
+ ///
+ /// ```ignore
+ /// make_param_ops!(
+ ///     /// Documentation for new param ops.
+ ///     PARAM_OPS_MYTYPE, // Name for the static.
+ ///     MyType // A type which implements [`ModuleParam`].
+ /// );
+ /// ```
+ macro_rules! make_param_ops {
+     ($ops:ident, $ty:ty) => {
+         #[doc(hidden)]
+         pub static $ops: $crate::bindings::kernel_param_ops = $crate::bindings::kernel_param_ops {
+             flags: 0,
+             set: Some(set_param::<$ty>),
+             get: None,
+             free: None,
+         };
+     };
+ }
+
+ make_param_ops!(PARAM_OPS_I8, i8);
+ make_param_ops!(PARAM_OPS_U8, u8);
+ make_param_ops!(PARAM_OPS_I16, i16);
+ make_param_ops!(PARAM_OPS_U16, u16);
+ make_param_ops!(PARAM_OPS_I32, i32);
+ make_param_ops!(PARAM_OPS_U32, u32);
+ make_param_ops!(PARAM_OPS_I64, i64);
+ make_param_ops!(PARAM_OPS_U64, u64);
+ make_param_ops!(PARAM_OPS_ISIZE, isize);
+ make_param_ops!(PARAM_OPS_USIZE, usize);
diff --cc rust/kernel/str.rs
index 6fcc9d47f12e,a1a3581eb546..fa87779d2253
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@@ -10,11 -10,11 +10,13 @@@ use crate::
  };
  use core::{
      marker::PhantomData,
 -    ops::{self, Deref, DerefMut, Index},
 +    ops::{Deref, DerefMut, Index},
  };

 +pub use crate::prelude::CStr;
 +
+ pub mod parse_int;
+
  /// Byte string without UTF-8 validity guarantee.
  #[repr(transparent)]
  pub struct BStr([u8]);
diff --cc rust/macros/module.rs
index 49131ff3e097,d62e9c1e2a89..80cb9b16f5aa
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@@ -84,8 -92,96 +92,96 @@@ impl<'a> ModInfoBuilder<'a>
      }

      fn emit(&mut self, field: &str, content: &str) {
-         self.emit_only_builtin(field, content);
-         self.emit_only_loadable(field, content);
+         self.emit_internal(field, content, false);
+     }
+
+     fn emit_internal(&mut self, field: &str, content: &str, param: bool) {
+         self.emit_only_builtin(field, content, param);
+         self.emit_only_loadable(field, content, param);
+     }
+
+     fn emit_param(&mut self, field: &str, param: &str, content: &str) {
+         let content = format!("{param}:{content}", param = param, content = content);
+         self.emit_internal(field, &content, true);
+     }
+
+     fn emit_params(&mut self, info: &ModuleInfo) {
+         let Some(params) = &info.params else {
+             return;
+         };
+
+         for param in params {
+             let ops = param_ops_path(&param.ptype);
+
+             // Note: The spelling of these fields is dictated by the user space
+             // tool `modinfo`.
+             self.emit_param("parmtype", &param.name, &param.ptype);
+             self.emit_param("parm", &param.name, &param.description);
+
+             write!(
+                 self.param_buffer,
+                 "
+                 pub(crate) static {param_name}:
+                     ::kernel::module_param::ModuleParamAccess<{param_type}> =
+                         ::kernel::module_param::ModuleParamAccess::new({param_default});
+
+                 const _: () = {{
+                     #[link_section = \"__param\"]
+                     #[used]
+                     static __{module_name}_{param_name}_struct:
+                         ::kernel::module_param::KernelParam =
+                         ::kernel::module_param::KernelParam::new(
+                             ::kernel::bindings::kernel_param {{
+                                 name: if ::core::cfg!(MODULE) {{
 -                                    ::kernel::c_str!(\"{param_name}\").as_bytes_with_nul()
++                                    ::kernel::c_str!(\"{param_name}\").to_bytes_with_nul()
+                                 }} else {{
+                                     ::kernel::c_str!(\"{module_name}.{param_name}\")
 -                                        .as_bytes_with_nul()
++                                        .to_bytes_with_nul()
+                                 }}.as_ptr(),
+                                 // SAFETY: `__this_module` is constructed by the kernel at load
+                                 // time and will not be freed until the module is unloaded.
+                                 #[cfg(MODULE)]
+                                 mod_: unsafe {{
+                                     core::ptr::from_ref(&::kernel::bindings::__this_module)
+                                         .cast_mut()
+                                 }},
+                                 #[cfg(not(MODULE))]
+                                 mod_: ::core::ptr::null_mut(),
+                                 ops: core::ptr::from_ref(&{ops}),
+                                 perm: 0, // Will not appear in sysfs
+                                 level: -1,
+                                 flags: 0,
+                                 __bindgen_anon_1: ::kernel::bindings::kernel_param__bindgen_ty_1 {{
+                                     arg: {param_name}.as_void_ptr()
+                                 }},
+                             }}
+                         );
+                 }};
+                 ",
+                 module_name = info.name,
+                 param_type = param.ptype,
+                 param_default = param.default,
+                 param_name = param.name,
+                 ops = ops,
+             )
+             .unwrap();
+         }
+     }
+ }
+
+ fn param_ops_path(param_type: &str) -> &'static str {
+     match param_type {
+         "i8" => "::kernel::module_param::PARAM_OPS_I8",
+         "u8" => "::kernel::module_param::PARAM_OPS_U8",
+         "i16" => "::kernel::module_param::PARAM_OPS_I16",
+         "u16" => "::kernel::module_param::PARAM_OPS_U16",
+         "i32" => "::kernel::module_param::PARAM_OPS_I32",
+         "u32" => "::kernel::module_param::PARAM_OPS_U32",
+         "i64" => "::kernel::module_param::PARAM_OPS_I64",
+         "u64" => "::kernel::module_param::PARAM_OPS_U64",
+         "isize" => "::kernel::module_param::PARAM_OPS_ISIZE",
+         "usize" => "::kernel::module_param::PARAM_OPS_USIZE",
+         t => panic!("Unsupported parameter type {}", t),
      }
  }

@@@ -98,7 -205,50 +205,51 @@@ struct ModuleInfo
      description: Option<String>,
      alias: Option<Vec<String>>,
      firmware: Option<Vec<String>>,
 +    imports_ns: Option<Vec<String>>,
+     params: Option<Vec<Parameter>>,
+ }
+
+ #[derive(Debug)]
+ struct Parameter {
+     name: String,
+     ptype: String,
+     default: String,
+     description: String,
+ }
+
+ fn expect_params(it: &mut token_stream::IntoIter) -> Vec<Parameter> {
+     let params = expect_group(it);
+     assert_eq!(params.delimiter(), Delimiter::Brace);
+     let mut it = params.stream().into_iter();
+     let mut parsed = Vec::new();
+
+     loop {
+         let param_name = match it.next() {
+             Some(TokenTree::Ident(ident)) => ident.to_string(),
+             Some(_) => panic!("Expected Ident or end"),
+             None => break,
+         };
+
+         assert_eq!(expect_punct(&mut it), ':');
+         let param_type = expect_ident(&mut it);
+         let group = expect_group(&mut it);
+         assert_eq!(group.delimiter(), Delimiter::Brace);
+         assert_eq!(expect_punct(&mut it), ',');
+
+         let mut param_it = group.stream().into_iter();
+         let param_default = expect_param_default(&mut param_it);
+         let param_description = expect_string_field(&mut param_it, "description");
+         expect_end(&mut param_it);
+
+         parsed.push(Parameter {
+             name: param_name,
+             ptype: param_type,
+             default: param_default,
+             description: param_description,
+         })
+     }
+
+     parsed
  }

  impl ModuleInfo {
@@@ -113,7 -263,7 +264,8 @@@
              "license",
              "alias",
              "firmware",
 +            "imports_ns",
+             "params",
          ];
          const REQUIRED_KEYS: &[&str] = &["type", "name", "license"];
          let mut seen_keys = Vec::new();
@@@ -139,7 -289,7 +291,8 @@@
                  "license" => info.license = expect_string_ascii(it),
                  "alias" => info.alias = Some(expect_string_array(it)),
                  "firmware" => info.firmware = Some(expect_string_array(it)),
 +                "imports_ns" => info.imports_ns = Some(expect_string_array(it)),
+                 "params" => info.params = Some(expect_params(it)),
                  _ => panic!("Unknown key \"{key}\". Valid keys are: {EXPECTED_KEYS:?}."),
              }

@@@ -179,30 -329,25 +332,30 @@@ pub(crate) fn module(ts: TokenStream) -
      // Rust does not allow hyphens in identifiers, use underscore instead.
      let ident = info.name.replace('-', "_");
      let mut modinfo = ModInfoBuilder::new(ident.as_ref());
-     if let Some(authors) = info.authors {
+     if let Some(authors) = &info.authors {
          for author in authors {
-             modinfo.emit("author", &author);
+             modinfo.emit("author", author);
          }
      }
-     if let Some(description) = info.description {
-         modinfo.emit("description", &description);
+     if let Some(description) = &info.description {
+         modinfo.emit("description", description);
      }
      modinfo.emit("license", &info.license);
-     if let Some(aliases) = info.alias {
+     if let Some(aliases) = &info.alias {
          for alias in aliases {
-             modinfo.emit("alias", &alias);
+             modinfo.emit("alias", alias);
          }
      }
-     if let Some(firmware) = info.firmware {
+     if let Some(firmware) = &info.firmware {
          for fw in firmware {
-             modinfo.emit("firmware", &fw);
+             modinfo.emit("firmware", fw);
          }
      }
-     if let Some(imports) = info.imports_ns {
++    if let Some(imports) = &info.imports_ns {
 +        for ns in imports {
-             modinfo.emit("import_ns", &ns);
++            modinfo.emit("import_ns", ns);
 +        }
 +    }

      // Built-in modules also export the `file` modinfo string.
      let file =