From nobody Tue Apr 7 18:46:39 2026 Received: from mail-dy1-f172.google.com (mail-dy1-f172.google.com [74.125.82.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 70A8333A6EC for ; Thu, 26 Feb 2026 23:47:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772149667; cv=none; b=s3xBgwiH9kVRTVlrvbu+la9/afdIj8fXqixCNZVVZjC6CyJejdL55yGXElJogzTE5EbZ4V0KIyjpEANt2XGd3lCl4bcLwOtdpfrRD51IZA/ArRKa0XXB3zFamWmfSTaymEzr4iy2HlC8U+j5xciTzPAUGJ9OZ4GA35Eto86lmjU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772149667; c=relaxed/simple; bh=xFtVJPjb1lCf06i8AWnkVR51MqrSe6UEn+2i41YDHgE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hYwah+nRsXWTbIYpXtJERGEGSQrW4/uYhL0IGY/fj/UN/KCcJzAshF3fOsFAnT50hJC+FZ4PN5VyLKYuk6yV1VxpFMexFRT6+QMyclxj279K7S3pu3tdH9NZhlvm7Ns+BdCAVPdVLE0lpfKROD0z+QovAdItAeEZO+m6VT9ob8M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=K9nqjOSA; arc=none smtp.client-ip=74.125.82.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="K9nqjOSA" Received: by mail-dy1-f172.google.com with SMTP id 5a478bee46e88-2bdcfbd0779so1699913eec.0 for ; Thu, 26 Feb 2026 15:47:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1772149665; x=1772754465; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=EpIeoheh9kwABfSNbiyNPrL4mJinCWikDVLVci1HHt8=; b=K9nqjOSAih+SH5bFtlfEcL/2quri6A8287JDxDswMn7HZkmxlZ0QRiwFxjqmEUhi2Z vlQhI0h9PapS2uOqs7oVZJBZaxdJ4qGEpdHPQi8mdEKSVLktvPP0CLzlUTuKj9DZ2mGP fOCaSLlZre906qf3nWTN2i9ahuCXEmO5Ptu4NHKKJ7iIo8HJKXrLooJHqdqZI3T+OCvs ajcHKnxaUgQXlQw/RXIk9EyWlZneH2aTT8Tcux0qC/efNSwP5tRUpWdyLt0suMWUdaiC Ug83Ni+N87mC0m3vsq5pyxVmj6gulTjtFaDBqhWhP11J5v5PdU+VszWpcsB+W9Cmzwvv onqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772149665; x=1772754465; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=EpIeoheh9kwABfSNbiyNPrL4mJinCWikDVLVci1HHt8=; b=DLLZ5GZXMQ2d3P7eCyWDCnBWf29vI9Kyrd7Wor4X11S7pT1PpVnlWdlRxATt2bNS0B jqruy09E8KiS6YC0VB+XJFJQKbLTzhUaLSunDrlBF2FuHP48cUVtaSjAPoL0BOEfJztQ pu3e4oiWTg04TDv03VjXbMN2ytAPyhtXUZwmi6M5R5RSvtS7YK7aViJCcqWSsjHqUBvj zJFI9KRHvhdrdIxrfXn9RGfxlDR4DOLRC6TJypscgI+SgPAI+DgwW2rCMarC4V9eOqka tSGIY8zHCuoK3T3rc35OU5oTAid/ua6nftU9gIdRmuPgTHvbeyMq9lAhnCiNte+fu9sM h8lA== X-Forwarded-Encrypted: i=1; AJvYcCV1LRkTwFnUpL5YJ7bS8okQu/t+tjK2FT1os4GE0teB5bALvsCYMOtSsD4Xm87N6yFT9+h4b24/mv/1hCA=@vger.kernel.org X-Gm-Message-State: AOJu0YwvH19p7aJTRoJTHmQBn7ttdT4dBH9OevtmgzTzgm+hL6dpjMY6 7ehgRkTpWR3x9O8eT+SoeEF33Wye91/Dc/FjnojpylmdFe7zEYVHYeQP X-Gm-Gg: ATEYQzwsSZH7X2Y5vAwO4HjO/SebKOD7TBNfD/gXqPTD2yhowJaJWkmvJ3/+VbsDuyM K4Mmz2lvPhsomJv6oolqthg8OA/ski+/UG5baBMr/H0k8Y6QF5VaGw7uoa92ijPQmWYExOPvLuY k4KOa/AZqyUUKOYrpaYNmiH1FLjw6qKU0DCGoeycaYLr3j6Pr3qQ+Cu8j42VMZGxiadzH0Xs6RC 74iHv7jhgOC1sG3X5faG0IjTi31zYRrQKnrskGwXkdzZTnGJtJWm05ZCV/O4MkYVIEjf5EsUVAF PDkmlIEIcfxtjQcndJR5ST8cHyloYIpVLCsbnhrekuyOeABfVBT6QkHApBDAWjgtz15OyuIk7K7 zBgTrUNh/85jQQ0vFcTZFdJiwDw2KXFjmkN67qnjeKb+jIUkM+lWfrR6tPxsMsiHOFZJKNvHRf5 DruBpuRY2/kXKPTqN/nYLP9EJqRj9YOYlDUiMXpg4ndrR7bAGEiGFheFi9bulIaKAUpoI46qtMc g== X-Received: by 2002:a05:7300:3b24:b0:2ba:75f5:72a2 with SMTP id 5a478bee46e88-2bde1b4def2mr341086eec.2.1772149664426; Thu, 26 Feb 2026 15:47:44 -0800 (PST) Received: from localhost (99-122-55-39.lightspeed.sntcca.sbcglobal.net. [99.122.55.39]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2bdd1f23be8sm2683786eec.20.2026.02.26.15.47.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 26 Feb 2026 15:47:44 -0800 (PST) From: Matthew Wood To: Miguel Ojeda , Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen Cc: Aaron Tomlin , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Tamir Duberstein , David Gow , =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= , linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 6/8] rust: macros: add early_param support to module! macro Date: Thu, 26 Feb 2026 15:47:32 -0800 Message-ID: <20260226234736.428341-7-thepacketgeek@gmail.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260226234736.428341-1-thepacketgeek@gmail.com> References: <20260226234736.428341-1-thepacketgeek@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Allow module parameters to be registered as early boot command-line parameters via the existing __setup infrastructure. Add an optional `early_param` field to the parameter block in the module! macro. When specified, the macro generates: - A setup callback that calls ModuleParam::from_setup_arg() and stores the result via ModuleParamAccess::set_value(). - A static string in .init.rodata with the command-line prefix. - An ObsKernelParam entry in the .init.setup section linking the two together. The generated code is gated behind #[cfg(not(MODULE))] since __setup parameters are only meaningful for built-in modules =E2=80=94 loadable modu= les receive their parameters through the standard module_param mechanism. Signed-off-by: Matthew Wood --- rust/macros/lib.rs | 5 +++ rust/macros/module.rs | 81 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 0c36194d9971..83dcc89a425a 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -35,9 +35,14 @@ /// parameter_name: type { /// default: default_value, /// description: "Description", +/// early_param: "cmdline_prefix=3D", // optional /// } /// ``` /// +/// The optional `early_param` field registers the parameter as an early +/// boot command-line parameter via `__setup`. The value is the command-li= ne +/// prefix string (e.g. `"netconsole=3D"`). +/// /// `type` may be one of /// /// - [`i8`] diff --git a/rust/macros/module.rs b/rust/macros/module.rs index 0d76743741fb..4d2e144fa6de 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -38,6 +38,7 @@ struct ModInfoBuilder<'a> { counter: usize, ts: TokenStream, param_ts: TokenStream, + setup_ts: TokenStream, } =20 impl<'a> ModInfoBuilder<'a> { @@ -47,6 +48,7 @@ fn new(module: &'a str) -> Self { counter: 0, ts: TokenStream::new(), param_ts: TokenStream::new(), + setup_ts: TokenStream::new(), } } =20 @@ -204,6 +206,78 @@ fn emit_params(&mut self, info: &ModuleInfo) { }); } } + + fn emit_setup(&mut self, info: &ModuleInfo) { + let Some(params) =3D &info.params else { + return; + }; + + for param in params { + let Some(early_param) =3D ¶m.early_param else { + continue; + }; + + let setup_str_value =3D early_param.value(); + let param_name =3D ¶m.name; + + // Resolve `string` shorthand to the real `StringParam` type. + let param_type_str =3D param.ptype.to_token_stream().to_string= (); + let actual_type: Type =3D if param_type_str =3D=3D "string" { + parse_quote!(::kernel::module_param::StringParam) + } else { + param.ptype.clone() + }; + + // Create identifiers for the generated statics + let setup_fn_name =3D format_ident!("__setup_fn_{}", param_nam= e); + let setup_str_name =3D + format_ident!("__SETUP_STR_{}", param_name.to_string().to_= uppercase()); + let setup_name =3D format_ident!("__SETUP_{}", param_name.to_s= tring().to_uppercase()); + + // The setup string with null terminator + let setup_str_bytes =3D format!("{}\0", setup_str_value); + let setup_str_len =3D setup_str_bytes.len(); + let setup_str_lit =3D Literal::byte_string(setup_str_bytes.as_= bytes()); + + self.setup_ts.extend(quote! { + #[cfg(not(MODULE))] + const _: () =3D { + unsafe extern "C" fn #setup_fn_name( + val: *mut ::kernel::ffi::c_char, + ) -> ::kernel::ffi::c_int { + if val.is_null() { + return 0; + } + // SAFETY: The kernel passes a valid null-terminat= ed string from + // `static_command_line`. + match unsafe { + <#actual_type as ::kernel::module_param::Modul= eParam>::from_setup_arg( + val as *const _ + ) + } { + Ok(v) =3D> { + if module_parameters::#param_name.set_valu= e(v) { 1 } else { 0 } + } + Err(_) =3D> 0, + } + } + + #[link_section =3D ".init.rodata"] + #[used(compiler)] + static #setup_str_name: [u8; #setup_str_len] =3D *#set= up_str_lit; + + #[link_section =3D ".init.setup"] + #[used(compiler)] + static #setup_name: ::kernel::module_param::ObsKernelP= aram =3D + ::kernel::module_param::ObsKernelParam { + str_: #setup_str_name.as_ptr().cast(), + setup_func: ::core::option::Option::Some(#setu= p_fn_name), + early: 0, + }; + }; + }); + } + } } =20 fn param_ops_path(param_type: &str) -> Path { @@ -367,6 +441,7 @@ struct Parameter { ptype: Type, default: Expr, description: LitStr, + early_param: Option, } =20 impl Parse for Parameter { @@ -382,6 +457,7 @@ fn parse(input: ParseStream<'_>) -> Result { from fields; default [required] =3D> fields.parse()?, description [required] =3D> fields.parse()?, + early_param =3D> fields.parse()?, } =20 Ok(Self { @@ -389,6 +465,7 @@ fn parse(input: ParseStream<'_>) -> Result { ptype, default, description, + early_param, }) } } @@ -501,9 +578,11 @@ pub(crate) fn module(info: ModuleInfo) -> Result { modinfo.emit_only_builtin("file", &file, false); =20 modinfo.emit_params(&info); + modinfo.emit_setup(&info); =20 let modinfo_ts =3D modinfo.ts; let params_ts =3D modinfo.param_ts; + let setup_ts =3D modinfo.setup_ts; =20 let ident_init =3D format_ident!("__{ident}_init"); let ident_exit =3D format_ident!("__{ident}_exit"); @@ -678,5 +757,7 @@ unsafe fn __exit() { mod module_parameters { #params_ts } + + #setup_ts }) } --=20 2.52.0