@@ -26,6 +26,7 @@ struct ModInfoBuilder<'a> {
2626 module : & ' a str ,
2727 counter : usize ,
2828 buffer : String ,
29+ param_buffer : String ,
2930}
3031
3132impl < ' a > ModInfoBuilder < ' a > {
@@ -34,10 +35,11 @@ impl<'a> ModInfoBuilder<'a> {
3435 module,
3536 counter : 0 ,
3637 buffer : String :: new ( ) ,
38+ param_buffer : String :: new ( ) ,
3739 }
3840 }
3941
40- fn emit_base ( & mut self , field : & str , content : & str , builtin : bool ) {
42+ fn emit_base ( & mut self , field : & str , content : & str , builtin : bool , param : bool ) {
4143 let string = if builtin {
4244 // Built-in modules prefix their modinfo strings by `module.`.
4345 format ! (
@@ -51,8 +53,14 @@ impl<'a> ModInfoBuilder<'a> {
5153 format ! ( "{field}={content}\0 " )
5254 } ;
5355
56+ let buffer = if param {
57+ & mut self . param_buffer
58+ } else {
59+ & mut self . buffer
60+ } ;
61+
5462 write ! (
55- & mut self . buffer,
63+ buffer,
5664 "
5765 {cfg}
5866 #[doc(hidden)]
@@ -75,20 +83,119 @@ impl<'a> ModInfoBuilder<'a> {
7583 self . counter += 1 ;
7684 }
7785
78- fn emit_only_builtin ( & mut self , field : & str , content : & str ) {
79- self . emit_base ( field, content, true )
86+ fn emit_only_builtin ( & mut self , field : & str , content : & str , param : bool ) {
87+ self . emit_base ( field, content, true , param )
8088 }
8189
82- fn emit_only_loadable ( & mut self , field : & str , content : & str ) {
83- self . emit_base ( field, content, false )
90+ fn emit_only_loadable ( & mut self , field : & str , content : & str , param : bool ) {
91+ self . emit_base ( field, content, false , param )
8492 }
8593
8694 fn emit ( & mut self , field : & str , content : & str ) {
87- self . emit_only_builtin ( field, content) ;
88- self . emit_only_loadable ( field, content) ;
95+ self . emit_internal ( field, content, false ) ;
96+ }
97+
98+ fn emit_internal ( & mut self , field : & str , content : & str , param : bool ) {
99+ self . emit_only_builtin ( field, content, param) ;
100+ self . emit_only_loadable ( field, content, param) ;
101+ }
102+
103+ fn emit_param ( & mut self , field : & str , param : & str , content : & str ) {
104+ let content = format ! ( "{param}:{content}" , param = param, content = content) ;
105+ self . emit_internal ( field, & content, true ) ;
106+ }
107+
108+ fn emit_params ( & mut self , info : & ModuleInfo ) {
109+ let Some ( params) = & info. params else {
110+ return ;
111+ } ;
112+
113+ for param in params {
114+ let ops = param_ops_path ( & param. ptype ) ;
115+
116+ // Note: The spelling of these fields is dictated by the user space
117+ // tool `modinfo`.
118+ self . emit_param ( "parmtype" , & param. name , & param. ptype ) ;
119+ self . emit_param ( "parm" , & param. name , & param. description ) ;
120+
121+ write ! (
122+ self . param_buffer,
123+ "
124+ pub(crate) static {param_name}:
125+ ::kernel::module_param::ModuleParamAccess<{param_type}> =
126+ ::kernel::module_param::ModuleParamAccess::new({param_default});
127+
128+ const _: () = {{
129+ #[link_section = \" __param\" ]
130+ #[used]
131+ static __{module_name}_{param_name}_struct:
132+ ::kernel::module_param::KernelParam =
133+ ::kernel::module_param::KernelParam::new(
134+ ::kernel::bindings::kernel_param {{
135+ name: if ::core::cfg!(MODULE) {{
136+ ::kernel::c_str!(\" {param_name}\" ).as_bytes_with_nul()
137+ }} else {{
138+ ::kernel::c_str!(\" {module_name}.{param_name}\" )
139+ .as_bytes_with_nul()
140+ }}.as_ptr(),
141+ // SAFETY: `__this_module` is constructed by the kernel at load
142+ // time and will not be freed until the module is unloaded.
143+ #[cfg(MODULE)]
144+ mod_: unsafe {{
145+ core::ptr::from_ref(&::kernel::bindings::__this_module)
146+ .cast_mut()
147+ }},
148+ #[cfg(not(MODULE))]
149+ mod_: ::core::ptr::null_mut(),
150+ ops: core::ptr::from_ref(&{ops}),
151+ perm: 0, // Will not appear in sysfs
152+ level: -1,
153+ flags: 0,
154+ __bindgen_anon_1: ::kernel::bindings::kernel_param__bindgen_ty_1 {{
155+ arg: {param_name}.as_void_ptr()
156+ }},
157+ }}
158+ );
159+ }};
160+ " ,
161+ module_name = info. name,
162+ param_type = param. ptype,
163+ param_default = param. default ,
164+ param_name = param. name,
165+ ops = ops,
166+ )
167+ . unwrap ( ) ;
168+ }
169+ }
170+ }
171+
172+ fn param_ops_path ( param_type : & str ) -> & ' static str {
173+ match param_type {
174+ "i8" => "::kernel::module_param::PARAM_OPS_I8" ,
175+ "u8" => "::kernel::module_param::PARAM_OPS_U8" ,
176+ "i16" => "::kernel::module_param::PARAM_OPS_I16" ,
177+ "u16" => "::kernel::module_param::PARAM_OPS_U16" ,
178+ "i32" => "::kernel::module_param::PARAM_OPS_I32" ,
179+ "u32" => "::kernel::module_param::PARAM_OPS_U32" ,
180+ "i64" => "::kernel::module_param::PARAM_OPS_I64" ,
181+ "u64" => "::kernel::module_param::PARAM_OPS_U64" ,
182+ "isize" => "::kernel::module_param::PARAM_OPS_ISIZE" ,
183+ "usize" => "::kernel::module_param::PARAM_OPS_USIZE" ,
184+ t => panic ! ( "Unsupported parameter type {}" , t) ,
89185 }
90186}
91187
188+ fn expect_param_default ( param_it : & mut token_stream:: IntoIter ) -> String {
189+ assert_eq ! ( expect_ident( param_it) , "default" ) ;
190+ assert_eq ! ( expect_punct( param_it) , ':' ) ;
191+ let sign = try_sign ( param_it) ;
192+ let default = try_literal ( param_it) . expect ( "Expected default param value" ) ;
193+ assert_eq ! ( expect_punct( param_it) , ',' ) ;
194+ let mut value = sign. map ( String :: from) . unwrap_or_default ( ) ;
195+ value. push_str ( & default) ;
196+ value
197+ }
198+
92199#[ derive( Debug , Default ) ]
93200struct ModuleInfo {
94201 type_ : String ,
@@ -98,6 +205,50 @@ struct ModuleInfo {
98205 description : Option < String > ,
99206 alias : Option < Vec < String > > ,
100207 firmware : Option < Vec < String > > ,
208+ params : Option < Vec < Parameter > > ,
209+ }
210+
211+ #[ derive( Debug ) ]
212+ struct Parameter {
213+ name : String ,
214+ ptype : String ,
215+ default : String ,
216+ description : String ,
217+ }
218+
219+ fn expect_params ( it : & mut token_stream:: IntoIter ) -> Vec < Parameter > {
220+ let params = expect_group ( it) ;
221+ assert_eq ! ( params. delimiter( ) , Delimiter :: Brace ) ;
222+ let mut it = params. stream ( ) . into_iter ( ) ;
223+ let mut parsed = Vec :: new ( ) ;
224+
225+ loop {
226+ let param_name = match it. next ( ) {
227+ Some ( TokenTree :: Ident ( ident) ) => ident. to_string ( ) ,
228+ Some ( _) => panic ! ( "Expected Ident or end" ) ,
229+ None => break ,
230+ } ;
231+
232+ assert_eq ! ( expect_punct( & mut it) , ':' ) ;
233+ let param_type = expect_ident ( & mut it) ;
234+ let group = expect_group ( & mut it) ;
235+ assert_eq ! ( group. delimiter( ) , Delimiter :: Brace ) ;
236+ assert_eq ! ( expect_punct( & mut it) , ',' ) ;
237+
238+ let mut param_it = group. stream ( ) . into_iter ( ) ;
239+ let param_default = expect_param_default ( & mut param_it) ;
240+ let param_description = expect_string_field ( & mut param_it, "description" ) ;
241+ expect_end ( & mut param_it) ;
242+
243+ parsed. push ( Parameter {
244+ name : param_name,
245+ ptype : param_type,
246+ default : param_default,
247+ description : param_description,
248+ } )
249+ }
250+
251+ parsed
101252}
102253
103254impl ModuleInfo {
@@ -112,6 +263,7 @@ impl ModuleInfo {
112263 "license" ,
113264 "alias" ,
114265 "firmware" ,
266+ "params" ,
115267 ] ;
116268 const REQUIRED_KEYS : & [ & str ] = & [ "type" , "name" , "license" ] ;
117269 let mut seen_keys = Vec :: new ( ) ;
@@ -137,6 +289,7 @@ impl ModuleInfo {
137289 "license" => info. license = expect_string_ascii ( it) ,
138290 "alias" => info. alias = Some ( expect_string_array ( it) ) ,
139291 "firmware" => info. firmware = Some ( expect_string_array ( it) ) ,
292+ "params" => info. params = Some ( expect_params ( it) ) ,
140293 _ => panic ! ( "Unknown key \" {key}\" . Valid keys are: {EXPECTED_KEYS:?}." ) ,
141294 }
142295
@@ -199,7 +352,9 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
199352 // Built-in modules also export the `file` modinfo string.
200353 let file =
201354 std:: env:: var ( "RUST_MODFILE" ) . expect ( "Unable to fetch RUST_MODFILE environmental variable" ) ;
202- modinfo. emit_only_builtin ( "file" , & file) ;
355+ modinfo. emit_only_builtin ( "file" , & file, false ) ;
356+
357+ modinfo. emit_params ( & info) ;
203358
204359 format ! (
205360 "
@@ -363,15 +518,18 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
363518 __MOD.assume_init_drop();
364519 }}
365520 }}
366-
367521 {modinfo}
368522 }}
369523 }}
524+ mod module_parameters {{
525+ {params}
526+ }}
370527 " ,
371528 type_ = info. type_,
372529 name = info. name,
373530 ident = ident,
374531 modinfo = modinfo. buffer,
532+ params = modinfo. param_buffer,
375533 initcall_section = ".initcall6.init"
376534 )
377535 . parse ( )
0 commit comments