All of lore.kernel.org
 help / color / mirror / Atom feed
From: ojeda@kernel.org
To: Linus Torvalds <torvalds@linux-foundation.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: rust-for-linux@vger.kernel.org, linux-kbuild@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	Miguel Ojeda <ojeda@kernel.org>,
	Alex Gaynor <alex.gaynor@gmail.com>,
	Geoffrey Thomas <geofft@ldpreload.com>,
	Finn Behrens <me@kloenk.de>,
	Adam Bratschi-Kaye <ark.email@gmail.com>,
	Wedson Almeida Filho <wedsonaf@google.com>,
	Sumera Priyadarsini <sylphrenadin@gmail.com>
Subject: [PATCH 06/13] Rust: Module crate
Date: Wed, 14 Apr 2021 20:45:57 +0200	[thread overview]
Message-ID: <20210414184604.23473-7-ojeda@kernel.org> (raw)
In-Reply-To: <20210414184604.23473-1-ojeda@kernel.org>

From: Miguel Ojeda <ojeda@kernel.org>

Implements the `module!` macro that is used by Rust modules
to easily declare the equivalent information to the `MODULE_*`
macros in C modules, e.g.:

    module! {
        type: RustMinimal,
        name: b"rust_minimal",
        author: b"Rust for Linux Contributors",
        description: b"Rust minimal sample",
        license: b"GPL v2",
        params: {},
    }

This is a Rust procedural macro crate. It is a crate type that allows
to create syntax extensions. It runs at compile-time and can consume
as well as produce Rust syntax.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Geoffrey Thomas <geofft@ldpreload.com>
Signed-off-by: Geoffrey Thomas <geofft@ldpreload.com>
Co-developed-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
Co-developed-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Sumera Priyadarsini <sylphrenadin@gmail.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/Makefile  |   2 +
 rust/module.rs | 685 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 687 insertions(+)
 create mode 100644 rust/module.rs

diff --git a/rust/Makefile b/rust/Makefile
index 5b96462b4fef..3fd827d4ac17 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -3,6 +3,8 @@
 obj-$(CONFIG_RUST) += core.o compiler_builtins.o helpers.o
 extra-$(CONFIG_RUST) += exports_core_generated.h
 
+extra-$(CONFIG_RUST) += libmodule.so
+
 RUSTDOC = rustdoc
 
 quiet_cmd_rustdoc = RUSTDOC $<
diff --git a/rust/module.rs b/rust/module.rs
new file mode 100644
index 000000000000..076525a97c9e
--- /dev/null
+++ b/rust/module.rs
@@ -0,0 +1,685 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Proc macro crate implementing the [`module!`] magic.
+//!
+//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
+
+#![deny(clippy::complexity)]
+#![deny(clippy::correctness)]
+#![deny(clippy::perf)]
+#![deny(clippy::style)]
+
+use proc_macro::{token_stream, Delimiter, Group, TokenStream, TokenTree};
+
+fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {
+    if let Some(TokenTree::Ident(ident)) = it.next() {
+        Some(ident.to_string())
+    } else {
+        None
+    }
+}
+
+fn try_literal(it: &mut token_stream::IntoIter) -> Option<String> {
+    if let Some(TokenTree::Literal(literal)) = it.next() {
+        Some(literal.to_string())
+    } else {
+        None
+    }
+}
+
+fn try_byte_string(it: &mut token_stream::IntoIter) -> Option<String> {
+    try_literal(it).and_then(|byte_string| {
+        if byte_string.starts_with("b\"") && byte_string.ends_with('\"') {
+            Some(byte_string[2..byte_string.len() - 1].to_string())
+        } else {
+            None
+        }
+    })
+}
+
+fn expect_ident(it: &mut token_stream::IntoIter) -> String {
+    try_ident(it).expect("Expected Ident")
+}
+
+fn expect_punct(it: &mut token_stream::IntoIter) -> char {
+    if let TokenTree::Punct(punct) = it.next().expect("Reached end of token stream for Punct") {
+        punct.as_char()
+    } else {
+        panic!("Expected Punct");
+    }
+}
+
+fn expect_literal(it: &mut token_stream::IntoIter) -> String {
+    try_literal(it).expect("Expected Literal")
+}
+
+fn expect_group(it: &mut token_stream::IntoIter) -> Group {
+    if let TokenTree::Group(group) = it.next().expect("Reached end of token stream for Group") {
+        group
+    } else {
+        panic!("Expected Group");
+    }
+}
+
+fn expect_byte_string(it: &mut token_stream::IntoIter) -> String {
+    try_byte_string(it).expect("Expected byte string")
+}
+
+#[derive(Clone, PartialEq)]
+enum ParamType {
+    Ident(String),
+    Array { vals: String, max_length: usize },
+}
+
+fn expect_array_fields(it: &mut token_stream::IntoIter) -> ParamType {
+    assert_eq!(expect_punct(it), '<');
+    let vals = expect_ident(it);
+    assert_eq!(expect_punct(it), ',');
+    let max_length_str = expect_literal(it);
+    let max_length = max_length_str
+        .parse::<usize>()
+        .expect("Expected usize length");
+    assert_eq!(expect_punct(it), '>');
+    ParamType::Array { vals, max_length }
+}
+
+fn expect_type(it: &mut token_stream::IntoIter) -> ParamType {
+    if let TokenTree::Ident(ident) = it
+        .next()
+        .expect("Reached end of token stream for param type")
+    {
+        match ident.to_string().as_ref() {
+            "ArrayParam" => expect_array_fields(it),
+            _ => ParamType::Ident(ident.to_string()),
+        }
+    } else {
+        panic!("Expected Param Type")
+    }
+}
+
+fn expect_end(it: &mut token_stream::IntoIter) {
+    if it.next().is_some() {
+        panic!("Expected end");
+    }
+}
+
+fn get_ident(it: &mut token_stream::IntoIter, expected_name: &str) -> String {
+    assert_eq!(expect_ident(it), expected_name);
+    assert_eq!(expect_punct(it), ':');
+    let ident = expect_ident(it);
+    assert_eq!(expect_punct(it), ',');
+    ident
+}
+
+fn get_literal(it: &mut token_stream::IntoIter, expected_name: &str) -> String {
+    assert_eq!(expect_ident(it), expected_name);
+    assert_eq!(expect_punct(it), ':');
+    let literal = expect_literal(it);
+    assert_eq!(expect_punct(it), ',');
+    literal
+}
+
+fn get_group(it: &mut token_stream::IntoIter, expected_name: &str) -> Group {
+    assert_eq!(expect_ident(it), expected_name);
+    assert_eq!(expect_punct(it), ':');
+    let group = expect_group(it);
+    assert_eq!(expect_punct(it), ',');
+    group
+}
+
+fn get_byte_string(it: &mut token_stream::IntoIter, expected_name: &str) -> String {
+    assert_eq!(expect_ident(it), expected_name);
+    assert_eq!(expect_punct(it), ':');
+    let byte_string = expect_byte_string(it);
+    assert_eq!(expect_punct(it), ',');
+    byte_string
+}
+
+fn __build_modinfo_string_base(
+    module: &str,
+    field: &str,
+    content: &str,
+    variable: &str,
+    builtin: bool,
+) -> String {
+    let string = if builtin {
+        // Built-in modules prefix their modinfo strings by `module.`.
+        format!(
+            "{module}.{field}={content}",
+            module = module,
+            field = field,
+            content = content
+        )
+    } else {
+        // Loadable modules' modinfo strings go as-is.
+        format!("{field}={content}", field = field, content = content)
+    };
+
+    format!(
+        "
+            {cfg}
+            #[link_section = \".modinfo\"]
+            #[used]
+            pub static {variable}: [u8; {length}] = *b\"{string}\\0\";
+        ",
+        cfg = if builtin {
+            "#[cfg(not(MODULE))]"
+        } else {
+            "#[cfg(MODULE)]"
+        },
+        variable = variable,
+        length = string.len() + 1,
+        string = string,
+    )
+}
+
+fn __build_modinfo_string_variable(module: &str, field: &str) -> String {
+    format!("__{module}_{field}", module = module, field = field)
+}
+
+fn build_modinfo_string_only_builtin(module: &str, field: &str, content: &str) -> String {
+    __build_modinfo_string_base(
+        module,
+        field,
+        content,
+        &__build_modinfo_string_variable(module, field),
+        true,
+    )
+}
+
+fn build_modinfo_string_only_loadable(module: &str, field: &str, content: &str) -> String {
+    __build_modinfo_string_base(
+        module,
+        field,
+        content,
+        &__build_modinfo_string_variable(module, field),
+        false,
+    )
+}
+
+fn build_modinfo_string(module: &str, field: &str, content: &str) -> String {
+    build_modinfo_string_only_builtin(module, field, content)
+        + &build_modinfo_string_only_loadable(module, field, content)
+}
+
+fn build_modinfo_string_param(module: &str, field: &str, param: &str, content: &str) -> String {
+    let variable = format!(
+        "__{module}_{field}_{param}",
+        module = module,
+        field = field,
+        param = param
+    );
+    let content = format!("{param}:{content}", param = param, content = content);
+    __build_modinfo_string_base(module, field, &content, &variable, true)
+        + &__build_modinfo_string_base(module, field, &content, &variable, false)
+}
+
+fn permissions_are_readonly(perms: &str) -> bool {
+    let (radix, digits) = if let Some(n) = perms.strip_prefix("0x") {
+        (16, n)
+    } else if let Some(n) = perms.strip_prefix("0o") {
+        (8, n)
+    } else if let Some(n) = perms.strip_prefix("0b") {
+        (2, n)
+    } else {
+        (10, perms)
+    };
+    match u32::from_str_radix(digits, radix) {
+        Ok(perms) => perms & 0o222 == 0,
+        Err(_) => false,
+    }
+}
+
+fn param_ops_path(param_type: &str) -> &'static str {
+    match param_type {
+        "bool" => "kernel::module_param::PARAM_OPS_BOOL",
+        "i8" => "kernel::module_param::PARAM_OPS_I8",
+        "u8" => "kernel::module_param::PARAM_OPS_U8",
+        "i16" => "kernel::module_param::PARAM_OPS_I16",
+        "u16" => "kernel::module_param::PARAM_OPS_U16",
+        "i32" => "kernel::module_param::PARAM_OPS_I32",
+        "u32" => "kernel::module_param::PARAM_OPS_U32",
+        "i64" => "kernel::module_param::PARAM_OPS_I64",
+        "u64" => "kernel::module_param::PARAM_OPS_U64",
+        "isize" => "kernel::module_param::PARAM_OPS_ISIZE",
+        "usize" => "kernel::module_param::PARAM_OPS_USIZE",
+        "str" => "kernel::module_param::PARAM_OPS_STR",
+        t => panic!("Unrecognized type {}", t),
+    }
+}
+
+fn try_simple_param_val(
+    param_type: &str,
+) -> Box<dyn Fn(&mut token_stream::IntoIter) -> Option<String>> {
+    match param_type {
+        "bool" => Box::new(|param_it| try_ident(param_it)),
+        "str" => Box::new(|param_it| {
+            try_byte_string(param_it)
+                .map(|s| format!("kernel::module_param::StringParam::Ref(b\"{}\")", s))
+        }),
+        _ => Box::new(|param_it| try_literal(param_it)),
+    }
+}
+
+fn get_default(param_type: &ParamType, param_it: &mut token_stream::IntoIter) -> String {
+    let try_param_val = match param_type {
+        ParamType::Ident(ref param_type)
+        | ParamType::Array {
+            vals: ref param_type,
+            max_length: _,
+        } => try_simple_param_val(param_type),
+    };
+    assert_eq!(expect_ident(param_it), "default");
+    assert_eq!(expect_punct(param_it), ':');
+    let default = match param_type {
+        ParamType::Ident(_) => try_param_val(param_it).expect("Expected default param value"),
+        ParamType::Array {
+            vals: _,
+            max_length: _,
+        } => {
+            let group = expect_group(param_it);
+            assert_eq!(group.delimiter(), Delimiter::Bracket);
+            let mut default_vals = Vec::new();
+            let mut it = group.stream().into_iter();
+
+            while let Some(default_val) = try_param_val(&mut it) {
+                default_vals.push(default_val);
+                match it.next() {
+                    Some(TokenTree::Punct(punct)) => assert_eq!(punct.as_char(), ','),
+                    None => break,
+                    _ => panic!("Expected ',' or end of array default values"),
+                }
+            }
+
+            let mut default_array = "kernel::module_param::ArrayParam::create(&[".to_string();
+            default_array.push_str(
+                &default_vals
+                    .iter()
+                    .map(|val| val.to_string())
+                    .collect::<Vec<String>>()
+                    .join(","),
+            );
+            default_array.push_str("])");
+            default_array
+        }
+    };
+    assert_eq!(expect_punct(param_it), ',');
+    default
+}
+
+fn generated_array_ops_name(vals: &str, max_length: usize) -> String {
+    format!(
+        "__generated_array_ops_{vals}_{max_length}",
+        vals = vals,
+        max_length = max_length
+    )
+}
+
+/// Declares a kernel module.
+///
+/// The `type` argument should be a type which implements the [`KernelModule`]
+/// trait. Also accepts various forms of kernel metadata.
+///
+/// [`KernelModule`]: ../kernel/trait.KernelModule.html
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use kernel::prelude::*;
+///
+/// module!{
+///     type: MyKernelModule,
+///     name: b"my_kernel_module",
+///     author: b"Rust for Linux Contributors",
+///     description: b"My very own kernel module!",
+///     license: b"GPL v2",
+///     params: {
+///        my_i32: i32 {
+///            default: 42,
+///            permissions: 0o000,
+///            description: b"Example of i32",
+///        },
+///        writeable_i32: i32 {
+///            default: 42,
+///            permissions: 0o644,
+///            description: b"Example of i32",
+///        },
+///    },
+/// }
+///
+/// struct MyKernelModule;
+///
+/// impl KernelModule for MyKernelModule {
+///     fn init() -> KernelResult<Self> {
+///         // If the parameter is writeable, then the kparam lock must be
+///         // taken to read the parameter:
+///         {
+///             let lock = THIS_MODULE.kernel_param_lock();
+///             pr_info!("i32 param is:  {}\n", writeable_i32.read(&lock));
+///         }
+///         // If the parameter is read only, it can be read without locking
+///         // the kernel parameters:
+///         pr_info!("i32 param is:  {}\n", my_i32.read());
+///         Ok(MyKernelModule)
+///     }
+/// }
+/// ```
+///
+/// # Supported parameter types
+///
+///   - `bool`: Corresponds to C `bool` param type.
+///   - `i8`: No equivalent C param type.
+///   - `u8`: Corresponds to C `char` param type.
+///   - `i16`: Corresponds to C `short` param type.
+///   - `u16`: Corresponds to C `ushort` param type.
+///   - `i32`: Corresponds to C `int` param type.
+///   - `u32`: Corresponds to C `uint` param type.
+///   - `i64`: No equivalent C param type.
+///   - `u64`: Corresponds to C `ullong` param type.
+///   - `isize`: No equivalent C param type.
+///   - `usize`: No equivalent C param type.
+///   - `str`: Corresponds to C `charp` param type. Reading returns a byte slice.
+///   - `ArrayParam<T,N>`: Corresponds to C parameters created using `module_param_array`. An array
+///     of `T`'s of length at **most** `N`.
+///
+/// `invbool` is unsupported: it was only ever used in a few modules.
+/// Consider using a `bool` and inverting the logic instead.
+#[proc_macro]
+pub fn module(ts: TokenStream) -> TokenStream {
+    let mut it = ts.into_iter();
+
+    let type_ = get_ident(&mut it, "type");
+    let name = get_byte_string(&mut it, "name");
+    let author = get_byte_string(&mut it, "author");
+    let description = get_byte_string(&mut it, "description");
+    let license = get_byte_string(&mut it, "license");
+    let params = get_group(&mut it, "params");
+
+    expect_end(&mut it);
+
+    assert_eq!(params.delimiter(), Delimiter::Brace);
+
+    let mut it = params.stream().into_iter();
+
+    let mut params_modinfo = String::new();
+
+    let mut array_types_to_generate = Vec::new();
+
+    loop {
+        let param_name = match it.next() {
+            Some(TokenTree::Ident(ident)) => ident.to_string(),
+            Some(_) => panic!("Expected Ident or end"),
+            None => break,
+        };
+
+        assert_eq!(expect_punct(&mut it), ':');
+        let param_type = expect_type(&mut it);
+        let group = expect_group(&mut it);
+        assert_eq!(expect_punct(&mut it), ',');
+
+        assert_eq!(group.delimiter(), Delimiter::Brace);
+
+        let mut param_it = group.stream().into_iter();
+        let param_default = get_default(&param_type, &mut param_it);
+        let param_permissions = get_literal(&mut param_it, "permissions");
+        let param_description = get_byte_string(&mut param_it, "description");
+        expect_end(&mut param_it);
+
+        // TODO: more primitive types
+        // TODO: other kinds: unsafes, etc.
+        let (param_kernel_type, ops): (String, _) = match param_type {
+            ParamType::Ident(ref param_type) => (
+                param_type.to_string(),
+                param_ops_path(&param_type).to_string(),
+            ),
+            ParamType::Array {
+                ref vals,
+                max_length,
+            } => {
+                array_types_to_generate.push((vals.clone(), max_length));
+                (
+                    format!("__rust_array_param_{}_{}", vals, max_length),
+                    generated_array_ops_name(vals, max_length),
+                )
+            }
+        };
+
+        params_modinfo.push_str(&build_modinfo_string_param(
+            &name,
+            "parmtype",
+            &param_name,
+            &param_kernel_type,
+        ));
+        params_modinfo.push_str(&build_modinfo_string_param(
+            &name,
+            "parm",
+            &param_name,
+            &param_description,
+        ));
+        let param_type_internal = match param_type {
+            ParamType::Ident(ref param_type) => match param_type.as_ref() {
+                "str" => "kernel::module_param::StringParam".to_string(),
+                other => other.to_string(),
+            },
+            ParamType::Array {
+                ref vals,
+                max_length,
+            } => format!(
+                "kernel::module_param::ArrayParam<{vals}, {max_length}>",
+                vals = vals,
+                max_length = max_length
+            ),
+        };
+        let read_func = if permissions_are_readonly(&param_permissions) {
+            format!(
+                "
+                    fn read(&self) -> &<{param_type_internal} as kernel::module_param::ModuleParam>::Value {{
+                        // SAFETY: Parameters do not need to be locked because they are read only or sysfs is not enabled.
+                        unsafe {{ <{param_type_internal} as kernel::module_param::ModuleParam>::value(&__{name}_{param_name}_value) }}
+                    }}
+                ",
+                name = name,
+                param_name = param_name,
+                param_type_internal = param_type_internal,
+            )
+        } else {
+            format!(
+                "
+                    fn read<'lck>(&self, lock: &'lck kernel::KParamGuard) -> &'lck <{param_type_internal} as kernel::module_param::ModuleParam>::Value {{
+                        // SAFETY: Parameters are locked by `KParamGuard`.
+                        unsafe {{ <{param_type_internal} as kernel::module_param::ModuleParam>::value(&__{name}_{param_name}_value) }}
+                    }}
+                ",
+                name = name,
+                param_name = param_name,
+                param_type_internal = param_type_internal,
+            )
+        };
+        let kparam = format!(
+            "
+                kernel::bindings::kernel_param__bindgen_ty_1 {{
+                    arg: unsafe {{ &__{name}_{param_name}_value }} as *const _ as *mut kernel::c_types::c_void,
+                }},
+            ",
+            name = name,
+            param_name = param_name,
+        );
+        params_modinfo.push_str(
+            &format!(
+                "
+                static mut __{name}_{param_name}_value: {param_type_internal} = {param_default};
+
+                struct __{name}_{param_name};
+
+                impl __{name}_{param_name} {{ {read_func} }}
+
+                const {param_name}: __{name}_{param_name} = __{name}_{param_name};
+
+                // Note: the C macro that generates the static structs for the `__param` section
+                // asks for them to be `aligned(sizeof(void *))`. However, that was put in place
+                // in 2003 in commit 38d5b085d2 (\"[PATCH] Fix over-alignment problem on x86-64\")
+                // to undo GCC over-alignment of static structs of >32 bytes. It seems that is
+                // not the case anymore, so we simplify to a transparent representation here
+                // in the expectation that it is not needed anymore.
+                // TODO: revisit this to confirm the above comment and remove it if it happened
+                #[repr(transparent)]
+                struct __{name}_{param_name}_RacyKernelParam(kernel::bindings::kernel_param);
+
+                unsafe impl Sync for __{name}_{param_name}_RacyKernelParam {{
+                }}
+
+                #[cfg(not(MODULE))]
+                const __{name}_{param_name}_name: *const kernel::c_types::c_char = b\"{name}.{param_name}\\0\" as *const _ as *const kernel::c_types::c_char;
+
+                #[cfg(MODULE)]
+                const __{name}_{param_name}_name: *const kernel::c_types::c_char = b\"{param_name}\\0\" as *const _ as *const kernel::c_types::c_char;
+
+                #[link_section = \"__param\"]
+                #[used]
+                static __{name}_{param_name}_struct: __{name}_{param_name}_RacyKernelParam = __{name}_{param_name}_RacyKernelParam(kernel::bindings::kernel_param {{
+                    name: __{name}_{param_name}_name,
+                    // SAFETY: `__this_module` is constructed by the kernel at load time and will not be freed until the module is unloaded.
+                    #[cfg(MODULE)]
+                    mod_: unsafe {{ &kernel::bindings::__this_module as *const _ as *mut _ }},
+                    #[cfg(not(MODULE))]
+                    mod_: core::ptr::null_mut(),
+                    ops: unsafe {{ &{ops} }} as *const kernel::bindings::kernel_param_ops,
+                    perm: {permissions},
+                    level: -1,
+                    flags: 0,
+                    __bindgen_anon_1: {kparam}
+                }});
+                ",
+                name = name,
+                param_type_internal = param_type_internal,
+                read_func = read_func,
+                param_default = param_default,
+                param_name = param_name,
+                ops = ops,
+                permissions = param_permissions,
+                kparam = kparam,
+            )
+        );
+    }
+
+    let mut generated_array_types = String::new();
+
+    for (vals, max_length) in array_types_to_generate {
+        let ops_name = generated_array_ops_name(&vals, max_length);
+        generated_array_types.push_str(&format!(
+            "
+                kernel::make_param_ops!(
+                    {ops_name},
+                    kernel::module_param::ArrayParam<{vals}, {{ {max_length} }}>
+                );
+            ",
+            ops_name = ops_name,
+            vals = vals,
+            max_length = max_length,
+        ));
+    }
+
+    let file =
+        std::env::var("RUST_MODFILE").expect("Unable to fetch RUST_MODFILE environmental variable");
+
+    format!(
+        "
+            /// The module name.
+            ///
+            /// Used by the printing macros, e.g. [`info!`].
+            const __MODULE_NAME: &[u8] = b\"{name}\\0\";
+
+            static mut __MOD: Option<{type_}> = None;
+
+            // SAFETY: `__this_module` is constructed by the kernel at load time and will not be freed until the module is unloaded.
+            #[cfg(MODULE)]
+            static THIS_MODULE: kernel::ThisModule = unsafe {{ kernel::ThisModule::from_ptr(&kernel::bindings::__this_module as *const _ as *mut _) }};
+            #[cfg(not(MODULE))]
+            static THIS_MODULE: kernel::ThisModule = unsafe {{ kernel::ThisModule::from_ptr(core::ptr::null_mut()) }};
+
+            // Loadable modules need to export the `{{init,cleanup}}_module` identifiers
+            #[cfg(MODULE)]
+            #[no_mangle]
+            pub extern \"C\" fn init_module() -> kernel::c_types::c_int {{
+                __init()
+            }}
+
+            #[cfg(MODULE)]
+            #[no_mangle]
+            pub extern \"C\" fn cleanup_module() {{
+                __exit()
+            }}
+
+            // Built-in modules are initialized through an initcall pointer
+            // and the identifiers need to be unique
+            #[cfg(not(MODULE))]
+            #[cfg(not(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS))]
+            #[link_section = \"{initcall_section}\"]
+            #[used]
+            pub static __{name}_initcall: extern \"C\" fn() -> kernel::c_types::c_int = __{name}_init;
+
+            #[cfg(not(MODULE))]
+            #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)]
+            global_asm!(
+                r#\".section \"{initcall_section}\", \"a\"
+                __{name}_initcall:
+                    .long   __{name}_init - .
+                    .previous
+                \"#
+            );
+
+            #[cfg(not(MODULE))]
+            #[no_mangle]
+            pub extern \"C\" fn __{name}_init() -> kernel::c_types::c_int {{
+                __init()
+            }}
+
+            #[cfg(not(MODULE))]
+            #[no_mangle]
+            pub extern \"C\" fn __{name}_exit() {{
+                __exit()
+            }}
+
+            fn __init() -> kernel::c_types::c_int {{
+                match <{type_} as KernelModule>::init() {{
+                    Ok(m) => {{
+                        unsafe {{
+                            __MOD = Some(m);
+                        }}
+                        return 0;
+                    }}
+                    Err(e) => {{
+                        return e.to_kernel_errno();
+                    }}
+                }}
+            }}
+
+            fn __exit() {{
+                unsafe {{
+                    // Invokes `drop()` on `__MOD`, which should be used for cleanup.
+                    __MOD = None;
+                }}
+            }}
+
+            {author}
+            {description}
+            {license}
+
+            // Built-in modules also export the `file` modinfo string
+            {file}
+
+            {params_modinfo}
+
+            {generated_array_types}
+        ",
+        type_ = type_,
+        name = name,
+        author = &build_modinfo_string(&name, "author", &author),
+        description = &build_modinfo_string(&name, "description", &description),
+        license = &build_modinfo_string(&name, "license", &license),
+        file = &build_modinfo_string_only_builtin(&name, "file", &file),
+        params_modinfo = params_modinfo,
+        generated_array_types = generated_array_types,
+        initcall_section = ".initcall6.init"
+    ).parse().expect("Error parsing formatted string into token stream.")
+}
-- 
2.17.1


  parent reply	other threads:[~2021-04-14 18:46 UTC|newest]

Thread overview: 201+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-14 18:45 [PATCH 00/13] [RFC] Rust support ojeda
2021-04-14 18:45 ` [PATCH 01/13] kallsyms: Support "big" kernel symbols (2-byte lengths) ojeda
2021-04-14 19:44   ` Matthew Wilcox
2021-04-14 19:59     ` Miguel Ojeda
2021-04-14 18:45 ` [PATCH 02/13] kallsyms: Increase maximum kernel symbol length to 512 ojeda
2021-04-14 23:48   ` Nick Desaulniers
2021-04-14 18:45 ` [PATCH 03/13] Makefile: Generate CLANG_FLAGS even in GCC builds ojeda
2021-04-14 18:59   ` Nathan Chancellor
2021-04-15 10:18     ` Miguel Ojeda
2021-04-14 23:46   ` Nick Desaulniers
2021-04-15  0:47     ` Miguel Ojeda
2021-04-14 18:45 ` [PATCH 04/13] Kbuild: Rust support ojeda
2021-04-14 23:19   ` Nick Desaulniers
2021-04-15  0:43     ` Miguel Ojeda
2021-04-15 18:03       ` Nick Desaulniers
2021-04-16 12:23         ` Miguel Ojeda
2021-04-17 19:35       ` Masahiro Yamada
2021-04-16 13:38   ` Peter Zijlstra
2021-04-16 17:05     ` Linus Torvalds
2021-04-16 17:47       ` Miguel Ojeda
2021-04-16 18:09         ` Al Viro
2021-04-16 18:57           ` Miguel Ojeda
2021-04-16 20:22             ` Willy Tarreau
2021-04-16 20:34               ` Connor Kuehl
2021-04-16 20:58                 ` Willy Tarreau
2021-04-16 21:39                   ` Miguel Ojeda
2021-04-16 22:04                     ` Willy Tarreau
2021-04-16 22:45                       ` Al Viro
2021-04-16 23:46                       ` Miguel Ojeda
2021-04-17  4:24                         ` Willy Tarreau
2021-04-17 15:38                           ` Miguel Ojeda
2021-04-16 21:19               ` Miguel Ojeda
2021-04-16 17:34     ` Miguel Ojeda
2021-04-19 19:58       ` David Sterba
2021-04-19 20:17         ` Matthew Wilcox
2021-04-19 21:03           ` Miguel Ojeda
2021-04-19 20:54         ` Miguel Ojeda
2021-04-14 18:45 ` [PATCH 05/13] Rust: Compiler builtins crate ojeda
2021-04-14 19:19   ` Linus Torvalds
2021-04-14 19:34     ` Miguel Ojeda
2021-04-14 18:45 ` ojeda [this message]
2021-04-14 18:45 ` [PATCH 07/13] Rust: Kernel crate ojeda
2021-04-14 19:31   ` Linus Torvalds
2021-04-14 19:50     ` Miguel Ojeda
2021-04-14 18:45 ` [PATCH 08/13] Rust: Export generated symbols ojeda
2021-04-14 18:46 ` [PATCH 09/13] Samples: Rust examples ojeda
2021-04-14 19:34   ` Linus Torvalds
2021-04-14 19:42     ` Miguel Ojeda
2021-04-14 19:49       ` Matthew Wilcox
2021-04-16 11:46       ` Andrej Shadura
2021-04-14 23:24     ` Nick Desaulniers
2021-04-15  7:10       ` Greg Kroah-Hartman
2021-04-15  7:39         ` Nick Desaulniers
2021-04-15 12:42         ` Miguel Ojeda
2021-04-16 13:07         ` Sven Van Asbroeck
2021-04-16 13:20           ` Greg Kroah-Hartman
2021-04-14 18:46 ` [PATCH 10/13] Documentation: Rust general information ojeda
2021-04-14 22:17   ` Nick Desaulniers
2021-04-14 23:34     ` Miguel Ojeda
2021-04-14 18:46 ` [PATCH 11/13] MAINTAINERS: Rust ojeda
2021-04-14 21:55   ` Nick Desaulniers
2021-04-14 22:02     ` Miguel Ojeda
2021-04-14 22:36   ` Nick Desaulniers
2021-04-14 18:46 ` [PATCH 12/13] Rust: add abstractions for Binder (WIP) ojeda
2021-04-14 18:46 ` [PATCH 13/13] Android: Binder IPC in Rust (WIP) ojeda
2021-04-14 19:44 ` [PATCH 00/13] [RFC] Rust support Linus Torvalds
2021-04-14 20:20   ` Miguel Ojeda
2021-04-15  1:38     ` Kees Cook
2021-04-15  8:26       ` David Laight
2021-04-15 18:08         ` Kees Cook
2021-04-15 12:39       ` Miguel Ojeda
2021-04-14 20:09 ` Matthew Wilcox
2021-04-14 20:21   ` Linus Torvalds
2021-04-14 20:35     ` Josh Triplett
2021-04-14 22:08     ` David Laight
2021-04-14 20:29   ` Miguel Ojeda
2021-04-18 15:31   ` Wedson Almeida Filho
2021-04-15  0:22 ` Nick Desaulniers
2021-04-15 10:05   ` Miguel Ojeda
2021-04-15 18:58 ` Peter Zijlstra
2021-04-16  2:22   ` Wedson Almeida Filho
2021-04-16  4:25     ` Al Viro
2021-04-16  5:02       ` Wedson Almeida Filho
2021-04-16  5:39         ` Paul Zimmerman
2021-04-16  7:46         ` Peter Zijlstra
2021-04-16  7:09     ` Peter Zijlstra
2021-04-17  5:23       ` comex
2021-04-17 12:46       ` David Laight
2021-04-17 14:51       ` Paolo Bonzini
2021-04-19  7:32         ` Peter Zijlstra
2021-04-19  7:53           ` Paolo Bonzini
2021-04-19  8:26             ` Peter Zijlstra
2021-04-19  8:35               ` Peter Zijlstra
2021-04-19  9:02               ` Paolo Bonzini
2021-04-19  9:36                 ` Peter Zijlstra
2021-04-19  9:40                   ` Paolo Bonzini
2021-04-19 11:01                     ` Will Deacon
2021-04-19 17:14                   ` Linus Torvalds
2021-04-19 18:38                     ` Paolo Bonzini
2021-04-19 18:50                       ` Linus Torvalds
2021-04-22 10:03     ` Linus Walleij
2021-04-22 14:09       ` David Laight
2021-04-22 15:24       ` Wedson Almeida Filho
2021-04-26  0:18         ` Linus Walleij
2021-04-26 14:26           ` Miguel Ojeda
2021-04-26 14:40           ` Wedson Almeida Filho
2021-04-26 16:03             ` Miguel Ojeda
2021-04-27 10:54             ` Linus Walleij
2021-04-27 11:13               ` Robin Randhawa
2021-04-29  1:52               ` Wedson Almeida Filho
2021-04-26 18:01           ` Miguel Ojeda
2021-04-22 21:28       ` Miguel Ojeda
2021-04-26  0:31         ` Linus Walleij
2021-04-26 18:18           ` Miguel Ojeda
2021-04-27 11:13             ` Linus Walleij
2021-04-28  2:51               ` Kyle Strand
2021-04-28  3:10               ` Miguel Ojeda
2021-05-04 21:21                 ` Linus Walleij
2021-05-04 23:30                   ` Miguel Ojeda
2021-05-05 11:34                     ` Linus Walleij
2021-05-05 14:17                       ` Miguel Ojeda
2021-05-05 15:13                         ` Enrico Weigelt, metux IT consult
2021-05-06 12:47                         ` Linus Walleij
2021-05-07 18:23                           ` Miguel Ojeda
2021-04-16  4:27   ` Boqun Feng
2021-04-16  6:04     ` Nick Desaulniers
2021-04-16 18:47       ` Paul E. McKenney
2021-04-19 20:35         ` Nick Desaulniers
2021-04-19 21:37           ` Paul E. McKenney
2021-04-19 22:03           ` Miguel Ojeda
2021-04-16 20:48     ` Josh Triplett
2021-04-16  8:16   ` Michal Kubecek
2021-04-16  9:29     ` Willy Tarreau
2021-04-16 11:24 ` Peter Zijlstra
2021-04-16 13:07   ` Wedson Almeida Filho
2021-04-16 14:19     ` Peter Zijlstra
2021-04-16 15:04       ` Miguel Ojeda
2021-04-16 15:43         ` Peter Zijlstra
2021-04-16 16:21           ` Miguel Ojeda
2021-04-16 15:33       ` Wedson Almeida Filho
2021-04-16 16:14         ` Willy Tarreau
2021-04-16 17:10           ` Miguel Ojeda
2021-04-16 17:18             ` Peter Zijlstra
2021-04-16 18:08               ` Matthew Wilcox
2021-04-17 11:17                 ` Peter Zijlstra
2021-04-17 11:46                   ` Willy Tarreau
2021-04-17 14:24                     ` Peter Zijlstra
2021-04-17 14:36                       ` Willy Tarreau
2021-04-17 13:46                   ` David Laight
2021-04-16 17:37             ` Willy Tarreau
2021-04-16 17:46               ` Connor Kuehl
2021-04-20  0:24               ` Nick Desaulniers
2021-04-20  3:47                 ` Willy Tarreau
2021-04-20  5:56                 ` Greg Kroah-Hartman
2021-04-20  6:16                   ` Willy Tarreau
2021-04-29 15:38                     ` peter enderborg
2021-04-17 13:53           ` Wedson Almeida Filho
2021-04-17 14:21             ` Willy Tarreau
2021-04-17 15:23               ` Miguel Ojeda
2021-04-18 15:51               ` Wedson Almeida Filho
2021-04-17 12:41       ` David Laight
2021-04-17 13:01         ` Wedson Almeida Filho
2021-04-16 15:03     ` Matthew Wilcox
2021-04-17 13:29       ` Wedson Almeida Filho
2021-04-16 15:58     ` Theodore Ts'o
2021-04-16 16:21       ` Wedson Almeida Filho
2021-04-17 15:11       ` Paolo Bonzini
2021-04-16 14:21   ` Miguel Ojeda
2021-04-17 20:42 ` Richard Weinberger
2021-04-28 18:34 ` Mariusz Ceier
2021-04-28 20:25   ` Nick Desaulniers
2021-04-28 21:21   ` David Laight
2021-04-29 11:14     ` Kajetan Puchalski
2021-04-29 11:25   ` Kajetan Puchalski
2021-04-29 14:06     ` Mariusz Ceier
2021-04-29 14:13       ` Sven Van Asbroeck
2021-04-29 14:26         ` Willy Tarreau
2021-04-29 15:06       ` Al Viro
2021-04-29 16:09         ` Mariusz Ceier
2021-04-30  6:39     ` Thomas Schoebel-Theuer
2021-04-30  8:30       ` David Laight
2021-05-05 13:58       ` Enrico Weigelt, metux IT consult
2021-05-05 14:41         ` Miguel Ojeda
2022-06-20 15:11 ` Olliver Schinagl
2022-06-27 17:44   ` Miguel Ojeda
2022-07-18  6:56     ` Olliver Schinagl
2022-07-20 19:23       ` Miguel Ojeda
2022-07-20 20:21         ` Nicolas Pitre
2022-07-27  7:47           ` Olliver Schinagl
2022-07-27 13:32             ` Nicolas Pitre
2022-07-27  8:05         ` Olliver Schinagl
2022-07-28 10:21           ` Gary Guo
2022-07-28 12:09             ` Greg Kroah-Hartman
2022-07-28 12:28               ` Gary Guo
2022-07-28 20:45               ` Olliver Schinagl
2022-07-29  8:04                 ` Greg Kroah-Hartman
2022-07-28 20:43             ` Olliver Schinagl
2022-10-15 14:16               ` Olliver Schinagl
2022-10-16  1:44                 ` Bagas Sanjaya
2022-10-16  1:50                   ` Bagas Sanjaya
2022-10-16 13:23                 ` Josh Triplett

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210414184604.23473-7-ojeda@kernel.org \
    --to=ojeda@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=ark.email@gmail.com \
    --cc=geofft@ldpreload.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=me@kloenk.de \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=sylphrenadin@gmail.com \
    --cc=torvalds@linux-foundation.org \
    --cc=wedsonaf@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.