1use std::ffi::CString;
4
5use proc_macro2::{
6 Literal,
7 TokenStream, };
9use quote::{
10 format_ident,
11 quote, };
13use syn::{
14 braced,
15 bracketed,
16 ext::IdentExt,
17 parse::{
18 Parse,
19 ParseStream, },
21 parse_quote,
22 punctuated::Punctuated,
23 Error,
24 Expr,
25 Ident,
26 LitStr,
27 Path,
28 Result,
29 Token,
30 Type, };
32
33use crate::helpers::*;
34
35struct ModInfoBuilder<'a> {
36 module: &'a str,
37 counter: usize,
38 ts: TokenStream,
39 param_ts: TokenStream,
40}
41
42impl<'a> ModInfoBuilder<'a> {
43 fn new(module: &'a str) -> Self {
44 ModInfoBuilder {
45 module,
46 counter: 0,
47 ts: TokenStream::new(),
48 param_ts: TokenStream::new(),
49 }
50 }
51
52 fn emit_base(&mut self, field: &str, content: &str, builtin: bool, param: bool) {
53 let string = if builtin {
54 format!("{module}.{field}={content}\0", module = self.module)
56 } else {
57 format!("{field}={content}\0")
59 };
60 let length = string.len();
61 let string = Literal::byte_string(string.as_bytes());
62 let cfg = if builtin {
63 quote!(#[cfg(not(MODULE))])
64 } else {
65 quote!(#[cfg(MODULE)])
66 };
67
68 let counter = format_ident!(
69 "__{module}_{counter}",
70 module = self.module.to_uppercase(),
71 counter = self.counter
72 );
73 let item = quote! {
74 #cfg
75 #[cfg_attr(not(target_os = "macos"), link_section = ".modinfo")]
76 #[used(compiler)]
77 pub static #counter: [u8; #length] = *#string;
78 };
79
80 if param {
81 self.param_ts.extend(item);
82 } else {
83 self.ts.extend(item);
84 }
85
86 self.counter += 1;
87 }
88
89 fn emit_only_builtin(&mut self, field: &str, content: &str, param: bool) {
90 self.emit_base(field, content, true, param)
91 }
92
93 fn emit_only_loadable(&mut self, field: &str, content: &str, param: bool) {
94 self.emit_base(field, content, false, param)
95 }
96
97 fn emit(&mut self, field: &str, content: &str) {
98 self.emit_internal(field, content, false);
99 }
100
101 fn emit_internal(&mut self, field: &str, content: &str, param: bool) {
102 self.emit_only_builtin(field, content, param);
103 self.emit_only_loadable(field, content, param);
104 }
105
106 fn emit_param(&mut self, field: &str, param: &str, content: &str) {
107 let content = format!("{param}:{content}");
108 self.emit_internal(field, &content, true);
109 }
110
111 fn emit_params(&mut self, info: &ModuleInfo) {
112 let Some(params) = &info.params else {
113 return;
114 };
115
116 for param in params {
117 let param_name_str = param.name.to_string();
118 let param_type_str = param.ptype.to_string();
119
120 let ops = param_ops_path(¶m_type_str);
121
122 self.emit_param("parmtype", ¶m_name_str, ¶m_type_str);
125 self.emit_param("parm", ¶m_name_str, ¶m.description.value());
126
127 let static_name = format_ident!("__{}_{}_struct", self.module, param.name);
128 let param_name_cstr =
129 CString::new(param_name_str).expect("name contains NUL-terminator");
130 let param_name_cstr_with_module =
131 CString::new(format!("{}.{}", self.module, param.name))
132 .expect("name contains NUL-terminator");
133
134 let param_name = ¶m.name;
135 let param_type = ¶m.ptype;
136 let param_default = ¶m.default;
137
138 self.param_ts.extend(quote! {
139 #[allow(non_upper_case_globals)]
140 pub(crate) static #param_name:
141 ::kernel::module_param::ModuleParamAccess<#param_type> =
142 ::kernel::module_param::ModuleParamAccess::new(#param_default);
143
144 const _: () = {
145 #[allow(non_upper_case_globals)]
146 #[link_section = "__param"]
147 #[used(compiler)]
148 static #static_name:
149 ::kernel::module_param::KernelParam =
150 ::kernel::module_param::KernelParam::new(
151 ::kernel::bindings::kernel_param {
152 name: kernel::str::as_char_ptr_in_const_context(
153 if ::core::cfg!(MODULE) {
154 #param_name_cstr
155 } else {
156 #param_name_cstr_with_module
157 }
158 ),
159 #[cfg(MODULE)]
162 mod_: unsafe {
163 core::ptr::from_ref(&::kernel::bindings::__this_module)
164 .cast_mut()
165 },
166 #[cfg(not(MODULE))]
167 mod_: ::core::ptr::null_mut(),
168 ops: core::ptr::from_ref(&#ops),
169 perm: 0, level: -1,
171 flags: 0,
172 __bindgen_anon_1: ::kernel::bindings::kernel_param__bindgen_ty_1 {
173 arg: #param_name.as_void_ptr()
174 },
175 }
176 );
177 };
178 });
179 }
180 }
181}
182
183fn param_ops_path(param_type: &str) -> Path {
184 match param_type {
185 "i8" => parse_quote!(::kernel::module_param::PARAM_OPS_I8),
186 "u8" => parse_quote!(::kernel::module_param::PARAM_OPS_U8),
187 "i16" => parse_quote!(::kernel::module_param::PARAM_OPS_I16),
188 "u16" => parse_quote!(::kernel::module_param::PARAM_OPS_U16),
189 "i32" => parse_quote!(::kernel::module_param::PARAM_OPS_I32),
190 "u32" => parse_quote!(::kernel::module_param::PARAM_OPS_U32),
191 "i64" => parse_quote!(::kernel::module_param::PARAM_OPS_I64),
192 "u64" => parse_quote!(::kernel::module_param::PARAM_OPS_U64),
193 "isize" => parse_quote!(::kernel::module_param::PARAM_OPS_ISIZE),
194 "usize" => parse_quote!(::kernel::module_param::PARAM_OPS_USIZE),
195 "bool" => parse_quote!(::kernel::module_param::PARAM_OPS_BOOL),
196 t => panic!("Unsupported parameter type {}", t),
197 }
198}
199
200macro_rules! parse_ordered_fields {
228 (@gen
229 [$input:expr]
230 [$([$name:ident; $key:ident; $parser:expr])*]
231 [$([$req_name:ident; $req_key:ident])*]
232 ) => {
233 $(let mut $name = None;)*
234
235 const EXPECTED_KEYS: &[&str] = &[$(stringify!($key),)*];
236 const REQUIRED_KEYS: &[&str] = &[$(stringify!($req_key),)*];
237
238 let span = $input.span();
239 let mut seen_keys = Vec::new();
240
241 while !$input.is_empty() {
242 let key = $input.call(Ident::parse_any)?;
243
244 if seen_keys.contains(&key) {
245 Err(Error::new_spanned(
246 &key,
247 format!(r#"duplicated key "{key}". Keys can only be specified once."#),
248 ))?
249 }
250
251 $input.parse::<Token![:]>()?;
252
253 match &*key.to_string() {
254 $(
255 stringify!($key) => $name = Some($parser),
256 )*
257 _ => {
258 Err(Error::new_spanned(
259 &key,
260 format!(r#"unknown key "{key}". Valid keys are: {EXPECTED_KEYS:?}."#),
261 ))?
262 }
263 }
264
265 $input.parse::<Token![,]>()?;
266 seen_keys.push(key);
267 }
268
269 for key in REQUIRED_KEYS {
270 if !seen_keys.iter().any(|e| e == key) {
271 Err(Error::new(span, format!(r#"missing required key "{key}""#)))?
272 }
273 }
274
275 let mut ordered_keys: Vec<&str> = Vec::new();
276 for key in EXPECTED_KEYS {
277 if seen_keys.iter().any(|e| e == key) {
278 ordered_keys.push(key);
279 }
280 }
281
282 if seen_keys != ordered_keys {
283 Err(Error::new(
284 span,
285 format!(r#"keys are not ordered as expected. Order them like: {ordered_keys:?}."#),
286 ))?
287 }
288
289 $(let $req_name = $req_name.expect("required field");)*
290 };
291
292 (@gen
294 [$input:expr] [$($tok:tt)*] [$($req:tt)*]
295 $key:ident as $name:ident [required] => $parser:expr,
296 $($rest:tt)*
297 ) => {
298 parse_ordered_fields!(
299 @gen [$input] [$($tok)* [$name; $key; $parser]] [$($req)* [$name; $key]] $($rest)*
300 )
301 };
302 (@gen
303 [$input:expr] [$($tok:tt)*] [$($req:tt)*]
304 $name:ident [required] => $parser:expr,
305 $($rest:tt)*
306 ) => {
307 parse_ordered_fields!(
308 @gen [$input] [$($tok)* [$name; $name; $parser]] [$($req)* [$name; $name]] $($rest)*
309 )
310 };
311
312 (@gen
314 [$input:expr] [$($tok:tt)*] [$($req:tt)*]
315 $key:ident as $name:ident => $parser:expr,
316 $($rest:tt)*
317 ) => {
318 parse_ordered_fields!(
319 @gen [$input] [$($tok)* [$name; $key; $parser]] [$($req)*] $($rest)*
320 )
321 };
322 (@gen
323 [$input:expr] [$($tok:tt)*] [$($req:tt)*]
324 $name:ident => $parser:expr,
325 $($rest:tt)*
326 ) => {
327 parse_ordered_fields!(
328 @gen [$input] [$($tok)* [$name; $name; $parser]] [$($req)*] $($rest)*
329 )
330 };
331
332 (from $input:expr; $($tok:tt)*) => {
333 parse_ordered_fields!(@gen [$input] [] [] $($tok)*)
334 }
335}
336
337struct Parameter {
338 name: Ident,
339 ptype: Ident,
340 default: Expr,
341 description: LitStr,
342}
343
344impl Parse for Parameter {
345 fn parse(input: ParseStream<'_>) -> Result<Self> {
346 let name = input.parse()?;
347 input.parse::<Token![:]>()?;
348 let ptype = input.parse()?;
349
350 let fields;
351 braced!(fields in input);
352
353 parse_ordered_fields! {
354 from fields;
355 default [required] => fields.parse()?,
356 description [required] => fields.parse()?,
357 }
358
359 Ok(Self {
360 name,
361 ptype,
362 default,
363 description,
364 })
365 }
366}
367
368pub(crate) struct ModuleInfo {
369 type_: Type,
370 license: AsciiLitStr,
371 name: AsciiLitStr,
372 authors: Option<Punctuated<AsciiLitStr, Token![,]>>,
373 description: Option<LitStr>,
374 alias: Option<Punctuated<AsciiLitStr, Token![,]>>,
375 firmware: Option<Punctuated<AsciiLitStr, Token![,]>>,
376 imports_ns: Option<Punctuated<AsciiLitStr, Token![,]>>,
377 params: Option<Punctuated<Parameter, Token![,]>>,
378}
379
380impl Parse for ModuleInfo {
381 fn parse(input: ParseStream<'_>) -> Result<Self> {
382 parse_ordered_fields!(
383 from input;
384 type as type_ [required] => input.parse()?,
385 name [required] => input.parse()?,
386 authors => {
387 let list;
388 bracketed!(list in input);
389 Punctuated::parse_terminated(&list)?
390 },
391 description => input.parse()?,
392 license [required] => input.parse()?,
393 alias => {
394 let list;
395 bracketed!(list in input);
396 Punctuated::parse_terminated(&list)?
397 },
398 firmware => {
399 let list;
400 bracketed!(list in input);
401 Punctuated::parse_terminated(&list)?
402 },
403 imports_ns => {
404 let list;
405 bracketed!(list in input);
406 Punctuated::parse_terminated(&list)?
407 },
408 params => {
409 let list;
410 braced!(list in input);
411 Punctuated::parse_terminated(&list)?
412 },
413 );
414
415 Ok(ModuleInfo {
416 type_,
417 license,
418 name,
419 authors,
420 description,
421 alias,
422 firmware,
423 imports_ns,
424 params,
425 })
426 }
427}
428
429pub(crate) fn module(info: ModuleInfo) -> Result<TokenStream> {
430 let ModuleInfo {
431 type_,
432 license,
433 name,
434 authors,
435 description,
436 alias,
437 firmware,
438 imports_ns,
439 params: _,
440 } = &info;
441
442 let ident = name.value().replace('-', "_");
444 let mut modinfo = ModInfoBuilder::new(ident.as_ref());
445 if let Some(authors) = authors {
446 for author in authors {
447 modinfo.emit("author", &author.value());
448 }
449 }
450 if let Some(description) = description {
451 modinfo.emit("description", &description.value());
452 }
453 modinfo.emit("license", &license.value());
454 if let Some(aliases) = alias {
455 for alias in aliases {
456 modinfo.emit("alias", &alias.value());
457 }
458 }
459 if let Some(firmware) = firmware {
460 for fw in firmware {
461 modinfo.emit("firmware", &fw.value());
462 }
463 }
464 if let Some(imports) = imports_ns {
465 for ns in imports {
466 modinfo.emit("import_ns", &ns.value());
467 }
468 }
469
470 let file =
472 std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable");
473 modinfo.emit_only_builtin("file", &file, false);
474
475 modinfo.emit_params(&info);
476
477 let modinfo_ts = modinfo.ts;
478 let params_ts = modinfo.param_ts;
479
480 let ident_init = format_ident!("__{ident}_init");
481 let ident_exit = format_ident!("__{ident}_exit");
482 let ident_initcall = format_ident!("__{ident}_initcall");
483 let initcall_section = ".initcall6.init";
484
485 let global_asm = format!(
486 r#".section "{initcall_section}", "a"
487 __{ident}_initcall:
488 .long __{ident}_init - .
489 .previous
490 "#
491 );
492
493 let name_cstr = CString::new(name.value()).expect("name contains NUL-terminator");
494
495 Ok(quote! {
496 const __LOG_PREFIX: &[u8] = #name_cstr.to_bytes_with_nul();
500
501 #[cfg(MODULE)]
504 static THIS_MODULE: ::kernel::ThisModule = unsafe {
505 extern "C" {
506 static __this_module: ::kernel::types::Opaque<::kernel::bindings::module>;
507 };
508
509 ::kernel::ThisModule::from_ptr(__this_module.get())
510 };
511
512 #[cfg(not(MODULE))]
513 static THIS_MODULE: ::kernel::ThisModule = unsafe {
514 ::kernel::ThisModule::from_ptr(::core::ptr::null_mut())
515 };
516
517 type LocalModule = #type_;
520
521 impl ::kernel::ModuleMetadata for #type_ {
522 const NAME: &'static ::kernel::str::CStr = #name_cstr;
523 }
524
525 #[doc(hidden)]
527 mod __module_init {
528 mod __module_init {
529 use pin_init::PinInit;
530
531 #[cfg(MODULE)]
536 #[used(compiler)]
537 static __IS_RUST_MODULE: () = ();
538
539 static mut __MOD: ::core::mem::MaybeUninit<super::super::LocalModule> =
540 ::core::mem::MaybeUninit::uninit();
541
542 #[cfg(MODULE)]
548 #[no_mangle]
549 #[link_section = ".init.text"]
550 pub unsafe extern "C" fn init_module() -> ::kernel::ffi::c_int {
551 unsafe { __init() }
555 }
556
557 #[cfg(MODULE)]
558 #[used(compiler)]
559 #[link_section = ".init.data"]
560 static __UNIQUE_ID___addressable_init_module: unsafe extern "C" fn() -> i32 =
561 init_module;
562
563 #[cfg(MODULE)]
564 #[no_mangle]
565 #[link_section = ".exit.text"]
566 pub extern "C" fn cleanup_module() {
567 unsafe { __exit() }
574 }
575
576 #[cfg(MODULE)]
577 #[used(compiler)]
578 #[link_section = ".exit.data"]
579 static __UNIQUE_ID___addressable_cleanup_module: extern "C" fn() = cleanup_module;
580
581 #[cfg(not(MODULE))]
584 #[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))]
585 #[link_section = #initcall_section]
586 #[used(compiler)]
587 pub static #ident_initcall: extern "C" fn() ->
588 ::kernel::ffi::c_int = #ident_init;
589
590 #[cfg(not(MODULE))]
591 #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)]
592 ::core::arch::global_asm!(#global_asm);
593
594 #[cfg(not(MODULE))]
595 #[no_mangle]
596 pub extern "C" fn #ident_init() -> ::kernel::ffi::c_int {
597 unsafe { __init() }
601 }
602
603 #[cfg(not(MODULE))]
604 #[no_mangle]
605 pub extern "C" fn #ident_exit() {
606 unsafe { __exit() }
613 }
614
615 unsafe fn __init() -> ::kernel::ffi::c_int {
619 let initer = <super::super::LocalModule as ::kernel::InPlaceModule>::init(
620 &super::super::THIS_MODULE
621 );
622 match unsafe { initer.__pinned_init(__MOD.as_mut_ptr()) } {
626 Ok(m) => 0,
627 Err(e) => e.to_errno(),
628 }
629 }
630
631 unsafe fn __exit() {
637 unsafe {
641 __MOD.assume_init_drop();
643 }
644 }
645
646 #modinfo_ts
647 }
648 }
649
650 mod module_parameters {
651 #params_ts
652 }
653 })
654}