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

Configure Feed

Select the types of activity you want to include in your feed.

rust: module: update the module macro with module parameter support

Allow module parameters to be declared in the rust `module!` macro.

Reviewed-by: Benno Lossin <lossin@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Tested-by: Daniel Gomez <da.gomez@samsung.com>
Signed-off-by: Daniel Gomez <da.gomez@kernel.org>

authored by

Andreas Hindborg and committed by
Daniel Gomez
0b24f974 3809d7a8

+224 -10
+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
··· 28 28 /// The `type` argument should be a type which implements the [`Module`] 29 29 /// trait. Also accepts various forms of kernel metadata. 30 30 /// 31 + /// The `params` field describe module parameters. Each entry has the form 32 + /// 33 + /// ```ignore 34 + /// parameter_name: type { 35 + /// default: default_value, 36 + /// description: "Description", 37 + /// } 38 + /// ``` 39 + /// 40 + /// `type` may be one of 41 + /// 42 + /// - [`i8`] 43 + /// - [`u8`] 44 + /// - [`i8`] 45 + /// - [`u8`] 46 + /// - [`i16`] 47 + /// - [`u16`] 48 + /// - [`i32`] 49 + /// - [`u32`] 50 + /// - [`i64`] 51 + /// - [`u64`] 52 + /// - [`isize`] 53 + /// - [`usize`] 54 + /// 31 55 /// C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h) 32 56 /// 33 57 /// [`Module`]: ../kernel/trait.Module.html ··· 68 44 /// description: "My very own kernel module!", 69 45 /// license: "GPL", 70 46 /// alias: ["alternate_module_name"], 47 + /// params: { 48 + /// my_parameter: i64 { 49 + /// default: 1, 50 + /// description: "This parameter has a default of 1", 51 + /// }, 52 + /// }, 71 53 /// } 72 54 /// 73 55 /// struct MyModule(i32); ··· 82 52 /// fn init(_module: &'static ThisModule) -> Result<Self> { 83 53 /// let foo: i32 = 42; 84 54 /// pr_info!("I contain: {}\n", foo); 55 + /// pr_info!("i32 param is: {}\n", module_parameters::my_parameter.read()); 85 56 /// Ok(Self(foo)) 86 57 /// } 87 58 /// }
+168 -10
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}\").as_bytes_with_nul() 129 + }} else {{ 130 + ::kernel::c_str!(\"{module_name}.{param_name}\") 131 + .as_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)] ··· 205 98 description: Option<String>, 206 99 alias: Option<Vec<String>>, 207 100 firmware: Option<Vec<String>>, 101 + params: Option<Vec<Parameter>>, 102 + } 103 + 104 + #[derive(Debug)] 105 + struct Parameter { 106 + name: String, 107 + ptype: String, 108 + default: String, 109 + description: String, 110 + } 111 + 112 + fn expect_params(it: &mut token_stream::IntoIter) -> Vec<Parameter> { 113 + let params = expect_group(it); 114 + assert_eq!(params.delimiter(), Delimiter::Brace); 115 + let mut it = params.stream().into_iter(); 116 + let mut parsed = Vec::new(); 117 + 118 + loop { 119 + let param_name = match it.next() { 120 + Some(TokenTree::Ident(ident)) => ident.to_string(), 121 + Some(_) => panic!("Expected Ident or end"), 122 + None => break, 123 + }; 124 + 125 + assert_eq!(expect_punct(&mut it), ':'); 126 + let param_type = expect_ident(&mut it); 127 + let group = expect_group(&mut it); 128 + assert_eq!(group.delimiter(), Delimiter::Brace); 129 + assert_eq!(expect_punct(&mut it), ','); 130 + 131 + let mut param_it = group.stream().into_iter(); 132 + let param_default = expect_param_default(&mut param_it); 133 + let param_description = expect_string_field(&mut param_it, "description"); 134 + expect_end(&mut param_it); 135 + 136 + parsed.push(Parameter { 137 + name: param_name, 138 + ptype: param_type, 139 + default: param_default, 140 + description: param_description, 141 + }) 142 + } 143 + 144 + parsed 208 145 } 209 146 210 147 impl ModuleInfo { ··· 263 112 "license", 264 113 "alias", 265 114 "firmware", 115 + "params", 266 116 ]; 267 117 const REQUIRED_KEYS: &[&str] = &["type", "name", "license"]; 268 118 let mut seen_keys = Vec::new(); ··· 289 137 "license" => info.license = expect_string_ascii(it), 290 138 "alias" => info.alias = Some(expect_string_array(it)), 291 139 "firmware" => info.firmware = Some(expect_string_array(it)), 140 + "params" => info.params = Some(expect_params(it)), 292 141 _ => panic!("Unknown key \"{key}\". Valid keys are: {EXPECTED_KEYS:?}."), 293 142 } 294 143 ··· 352 199 // Built-in modules also export the `file` modinfo string. 353 200 let file = 354 201 std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable"); 355 - modinfo.emit_only_builtin("file", &file); 202 + modinfo.emit_only_builtin("file", &file, false); 203 + 204 + modinfo.emit_params(&info); 356 205 357 206 format!( 358 207 " ··· 518 363 __MOD.assume_init_drop(); 519 364 }} 520 365 }} 521 - 522 366 {modinfo} 523 367 }} 368 + }} 369 + mod module_parameters {{ 370 + {params} 524 371 }} 525 372 ", 526 373 type_ = info.type_, 527 374 name = info.name, 528 375 ident = ident, 529 376 modinfo = modinfo.buffer, 377 + params = modinfo.param_buffer, 530 378 initcall_section = ".initcall6.init" 531 379 ) 532 380 .parse()