Skip to main content

macros/
module.rs

1// SPDX-License-Identifier: GPL-2.0
2
3use std::ffi::CString;
4
5use proc_macro2::{
6    Literal,
7    TokenStream, //
8};
9use quote::{
10    format_ident,
11    quote, //
12};
13use syn::{
14    braced,
15    bracketed,
16    ext::IdentExt,
17    parse::{
18        Parse,
19        ParseStream, //
20    },
21    parse_quote,
22    punctuated::Punctuated,
23    Error,
24    Expr,
25    Ident,
26    LitStr,
27    Path,
28    Result,
29    Token,
30    Type, //
31};
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            // Built-in modules prefix their modinfo strings by `module.`.
55            format!("{module}.{field}={content}\0", module = self.module)
56        } else {
57            // Loadable modules' modinfo strings go as-is.
58            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(&param_type_str);
121
122            // Note: The spelling of these fields is dictated by the user space
123            // tool `modinfo`.
124            self.emit_param("parmtype", &param_name_str, &param_type_str);
125            self.emit_param("parm", &param_name_str, &param.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 = &param.name;
135            let param_type = &param.ptype;
136            let param_default = &param.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                                // SAFETY: `__this_module` is constructed by the kernel at load
160                                // time and will not be freed until the module is unloaded.
161                                #[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, // Will not appear in sysfs
170                                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
200/// Parse fields that are required to use a specific order.
201///
202/// As fields must follow a specific order, we *could* just parse fields one by one by peeking.
203/// However the error message generated when implementing that way is not very friendly.
204///
205/// So instead we parse fields in an arbitrary order, but only enforce the ordering after parsing,
206/// and if the wrong order is used, the proper order is communicated to the user with error message.
207///
208/// Usage looks like this:
209/// ```ignore
210/// parse_ordered_fields! {
211///     from input;
212///
213///     // This will extract "foo: <field>" into a variable named "foo".
214///     // The variable will have type `Option<_>`.
215///     foo => <expression that parses the field>,
216///
217///     // If you need the variable name to be different than the key name.
218///     // This extracts "baz: <field>" into a variable named "bar".
219///     // You might want this if "baz" is a keyword.
220///     baz as bar => <expression that parse the field>,
221///
222///     // You can mark a key as required, and the variable will no longer be `Option`.
223///     // foobar will be of type `Expr` instead of `Option<Expr>`.
224///     foobar [required] => input.parse::<Expr>()?,
225/// }
226/// ```
227macro_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    // Handle required fields.
293    (@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    // Handle optional fields.
313    (@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    // Rust does not allow hyphens in identifiers, use underscore instead.
443    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    // Built-in modules also export the `file` modinfo string.
471    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        /// The module name.
497        ///
498        /// Used by the printing macros, e.g. [`info!`].
499        const __LOG_PREFIX: &[u8] = #name_cstr.to_bytes_with_nul();
500
501        // SAFETY: `__this_module` is constructed by the kernel at load time and will not be
502        // freed until the module is unloaded.
503        #[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        /// The `LocalModule` type is the type of the module created by `module!`,
518        /// `module_pci_driver!`, `module_platform_driver!`, etc.
519        type LocalModule = #type_;
520
521        impl ::kernel::ModuleMetadata for #type_ {
522            const NAME: &'static ::kernel::str::CStr = #name_cstr;
523        }
524
525        // Double nested modules, since then nobody can access the public items inside.
526        #[doc(hidden)]
527        mod __module_init {
528            mod __module_init {
529                use pin_init::PinInit;
530
531                /// The "Rust loadable module" mark.
532                //
533                // This may be best done another way later on, e.g. as a new modinfo
534                // key or a new section. For the moment, keep it simple.
535                #[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                // Loadable modules need to export the `{init,cleanup}_module` identifiers.
543                /// # Safety
544                ///
545                /// This function must not be called after module initialization, because it may be
546                /// freed after that completes.
547                #[cfg(MODULE)]
548                #[no_mangle]
549                #[link_section = ".init.text"]
550                pub unsafe extern "C" fn init_module() -> ::kernel::ffi::c_int {
551                    // SAFETY: This function is inaccessible to the outside due to the double
552                    // module wrapping it. It is called exactly once by the C side via its
553                    // unique name.
554                    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                    // SAFETY:
568                    // - This function is inaccessible to the outside due to the double
569                    //   module wrapping it. It is called exactly once by the C side via its
570                    //   unique name,
571                    // - furthermore it is only called after `init_module` has returned `0`
572                    //   (which delegates to `__init`).
573                    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                // Built-in modules are initialized through an initcall pointer
582                // and the identifiers need to be unique.
583                #[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                    // SAFETY: This function is inaccessible to the outside due to the double
598                    // module wrapping it. It is called exactly once by the C side via its
599                    // placement above in the initcall section.
600                    unsafe { __init() }
601                }
602
603                #[cfg(not(MODULE))]
604                #[no_mangle]
605                pub extern "C" fn #ident_exit() {
606                    // SAFETY:
607                    // - This function is inaccessible to the outside due to the double
608                    //   module wrapping it. It is called exactly once by the C side via its
609                    //   unique name,
610                    // - furthermore it is only called after `#ident_init` has
611                    //   returned `0` (which delegates to `__init`).
612                    unsafe { __exit() }
613                }
614
615                /// # Safety
616                ///
617                /// This function must only be called once.
618                unsafe fn __init() -> ::kernel::ffi::c_int {
619                    let initer = <super::super::LocalModule as ::kernel::InPlaceModule>::init(
620                        &super::super::THIS_MODULE
621                    );
622                    // SAFETY: No data race, since `__MOD` can only be accessed by this module
623                    // and there only `__init` and `__exit` access it. These functions are only
624                    // called once and `__exit` cannot be called before or during `__init`.
625                    match unsafe { initer.__pinned_init(__MOD.as_mut_ptr()) } {
626                        Ok(m) => 0,
627                        Err(e) => e.to_errno(),
628                    }
629                }
630
631                /// # Safety
632                ///
633                /// This function must
634                /// - only be called once,
635                /// - be called after `__init` has been called and returned `0`.
636                unsafe fn __exit() {
637                    // SAFETY: No data race, since `__MOD` can only be accessed by this module
638                    // and there only `__init` and `__exit` access it. These functions are only
639                    // called once and `__init` was already called.
640                    unsafe {
641                        // Invokes `drop()` on `__MOD`, which should be used for cleanup.
642                        __MOD.assume_init_drop();
643                    }
644                }
645
646                #modinfo_ts
647            }
648        }
649
650        mod module_parameters {
651            #params_ts
652        }
653    })
654}