diff options
Diffstat (limited to 'rust/macros/lib.rs')
| -rw-r--r-- | rust/macros/lib.rs | 303 |
1 files changed, 174 insertions, 129 deletions
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index a626b1145e5c..b38002151871 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -6,16 +6,21 @@ // and thus add a dependency on `include/config/RUSTC_VERSION_TEXT`, which is // touched by Kconfig when the version string from the compiler changes. +// Stable since Rust 1.88.0 under a different name, `proc_macro_span_file`, +// which was added in Rust 1.88.0. This is why `cfg_attr` is used here, i.e. +// to avoid depending on the full `proc_macro_span` on Rust >= 1.88.0. +#![cfg_attr(not(CONFIG_RUSTC_HAS_SPAN_FILE), feature(proc_macro_span))] + #[macro_use] mod quote; mod concat_idents; +mod export; +mod fmt; mod helpers; +mod kunit; mod module; mod paste; -mod pin_data; -mod pinned_drop; mod vtable; -mod zeroable; use proc_macro::TokenStream; @@ -24,40 +29,65 @@ use proc_macro::TokenStream; /// The `type` argument should be a type which implements the [`Module`] /// trait. Also accepts various forms of kernel metadata. /// +/// The `params` field describe module parameters. Each entry has the form +/// +/// ```ignore +/// parameter_name: type { +/// default: default_value, +/// description: "Description", +/// } +/// ``` +/// +/// `type` may be one of +/// +/// - [`i8`] +/// - [`u8`] +/// - [`i8`] +/// - [`u8`] +/// - [`i16`] +/// - [`u16`] +/// - [`i32`] +/// - [`u32`] +/// - [`i64`] +/// - [`u64`] +/// - [`isize`] +/// - [`usize`] +/// /// C header: [`include/linux/moduleparam.h`](srctree/include/linux/moduleparam.h) /// /// [`Module`]: ../kernel/trait.Module.html /// /// # Examples /// -/// ```ignore +/// ``` /// use kernel::prelude::*; /// /// module!{ /// type: MyModule, /// name: "my_kernel_module", -/// author: "Rust for Linux Contributors", +/// authors: ["Rust for Linux Contributors"], /// description: "My very own kernel module!", /// license: "GPL", /// alias: ["alternate_module_name"], +/// params: { +/// my_parameter: i64 { +/// default: 1, +/// description: "This parameter has a default of 1", +/// }, +/// }, /// } /// -/// struct MyModule; +/// struct MyModule(i32); /// /// impl kernel::Module for MyModule { -/// fn init() -> Result<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(Self) +/// fn init(_module: &'static ThisModule) -> Result<Self> { +/// let foo: i32 = 42; +/// pr_info!("I contain: {}\n", foo); +/// pr_info!("i32 param is: {}\n", module_parameters::my_parameter.read()); +/// Ok(Self(foo)) /// } /// } +/// # fn main() {} /// ``` /// /// ## Firmware @@ -69,13 +99,13 @@ use proc_macro::TokenStream; /// build an initramfs uses this information to put the firmware files into /// the initramfs image. /// -/// ```ignore +/// ``` /// use kernel::prelude::*; /// /// module!{ /// type: MyDeviceDriverModule, /// name: "my_device_driver_module", -/// author: "Rust for Linux Contributors", +/// authors: ["Rust for Linux Contributors"], /// description: "My device driver requires firmware", /// license: "GPL", /// firmware: ["my_device_firmware1.bin", "my_device_firmware2.bin"], @@ -84,16 +114,17 @@ use proc_macro::TokenStream; /// struct MyDeviceDriverModule; /// /// impl kernel::Module for MyDeviceDriverModule { -/// fn init() -> Result<Self> { +/// fn init(_module: &'static ThisModule) -> Result<Self> { /// Ok(Self) /// } /// } +/// # fn main() {} /// ``` /// /// # Supported argument types /// - `type`: type which implements the [`Module`] trait (required). /// - `name`: ASCII string literal of the name of the kernel module (required). -/// - `author`: string literal of the author of the kernel module. +/// - `authors`: array of ASCII string literals of the authors of the kernel module. /// - `description`: string literal of the description of the kernel module. /// - `license`: ASCII string literal of the license of the kernel module (required). /// - `alias`: array of ASCII string literals of the alias names of the kernel module. @@ -128,12 +159,12 @@ pub fn module(ts: TokenStream) -> TokenStream { /// used on the Rust side, it should not be possible to call the default /// implementation. This is done to ensure that we call the vtable methods /// through the C vtable, and not through the Rust vtable. Therefore, the -/// default implementation should call `kernel::build_error`, which prevents +/// default implementation should call `build_error!`, which prevents /// calls to this function at compile time: /// /// ```compile_fail -/// # use kernel::error::VTABLE_DEFAULT_ERROR; -/// kernel::build_error(VTABLE_DEFAULT_ERROR) +/// # // Intentionally missing `use`s to simplify `rusttest`. +/// build_error!(VTABLE_DEFAULT_ERROR) /// ``` /// /// Note that you might need to import [`kernel::error::VTABLE_DEFAULT_ERROR`]. @@ -142,7 +173,7 @@ pub fn module(ts: TokenStream) -> TokenStream { /// /// # Examples /// -/// ```ignore +/// ``` /// use kernel::error::VTABLE_DEFAULT_ERROR; /// use kernel::prelude::*; /// @@ -150,11 +181,11 @@ pub fn module(ts: TokenStream) -> TokenStream { /// #[vtable] /// pub trait Operations: Send + Sync + Sized { /// fn foo(&self) -> Result<()> { -/// kernel::build_error(VTABLE_DEFAULT_ERROR) +/// build_error!(VTABLE_DEFAULT_ERROR) /// } /// /// fn bar(&self) -> Result<()> { -/// kernel::build_error(VTABLE_DEFAULT_ERROR) +/// build_error!(VTABLE_DEFAULT_ERROR) /// } /// } /// @@ -179,6 +210,47 @@ pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream { vtable::vtable(attr, ts) } +/// Export a function so that C code can call it via a header file. +/// +/// Functions exported using this macro can be called from C code using the declaration in the +/// appropriate header file. It should only be used in cases where C calls the function through a +/// header file; cases where C calls into Rust via a function pointer in a vtable (such as +/// `file_operations`) should not use this macro. +/// +/// This macro has the following effect: +/// +/// * Disables name mangling for this function. +/// * Verifies at compile-time that the function signature matches the declaration in the header +/// file. +/// +/// You must declare the signature of the Rust function in a header file that is included by +/// `rust/bindings/bindings_helper.h`. +/// +/// This macro is *not* the same as the C macros `EXPORT_SYMBOL_*`. All Rust symbols are currently +/// automatically exported with `EXPORT_SYMBOL_GPL`. +#[proc_macro_attribute] +pub fn export(attr: TokenStream, ts: TokenStream) -> TokenStream { + export::export(attr, ts) +} + +/// Like [`core::format_args!`], but automatically wraps arguments in [`kernel::fmt::Adapter`]. +/// +/// This macro allows generating `fmt::Arguments` while ensuring that each argument is wrapped with +/// `::kernel::fmt::Adapter`, which customizes formatting behavior for kernel logging. +/// +/// Named arguments used in the format string (e.g. `{foo}`) are detected and resolved from local +/// bindings. All positional and named arguments are automatically wrapped. +/// +/// This macro is an implementation detail of other kernel logging macros like [`pr_info!`] and +/// should not typically be used directly. +/// +/// [`kernel::fmt::Adapter`]: ../kernel/fmt/struct.Adapter.html +/// [`pr_info!`]: ../kernel/macro.pr_info.html +#[proc_macro] +pub fn fmt(input: TokenStream) -> TokenStream { + fmt::fmt(input) +} + /// Concatenate two identifiers. /// /// This is useful in macros that need to declare or reference items with names @@ -187,12 +259,27 @@ pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream { /// /// # Examples /// -/// ```ignore -/// use kernel::macro::concat_idents; +/// ``` +/// # const binder_driver_return_protocol_BR_OK: u32 = 0; +/// # const binder_driver_return_protocol_BR_ERROR: u32 = 1; +/// # const binder_driver_return_protocol_BR_TRANSACTION: u32 = 2; +/// # const binder_driver_return_protocol_BR_REPLY: u32 = 3; +/// # const binder_driver_return_protocol_BR_DEAD_REPLY: u32 = 4; +/// # const binder_driver_return_protocol_BR_TRANSACTION_COMPLETE: u32 = 5; +/// # const binder_driver_return_protocol_BR_INCREFS: u32 = 6; +/// # const binder_driver_return_protocol_BR_ACQUIRE: u32 = 7; +/// # const binder_driver_return_protocol_BR_RELEASE: u32 = 8; +/// # const binder_driver_return_protocol_BR_DECREFS: u32 = 9; +/// # const binder_driver_return_protocol_BR_NOOP: u32 = 10; +/// # const binder_driver_return_protocol_BR_SPAWN_LOOPER: u32 = 11; +/// # const binder_driver_return_protocol_BR_DEAD_BINDER: u32 = 12; +/// # const binder_driver_return_protocol_BR_CLEAR_DEATH_NOTIFICATION_DONE: u32 = 13; +/// # const binder_driver_return_protocol_BR_FAILED_REPLY: u32 = 14; +/// use kernel::macros::concat_idents; /// /// macro_rules! pub_no_prefix { /// ($prefix:ident, $($newname:ident),+) => { -/// $(pub(crate) const $newname: u32 = kernel::macros::concat_idents!($prefix, $newname);)+ +/// $(pub(crate) const $newname: u32 = concat_idents!($prefix, $newname);)+ /// }; /// } /// @@ -222,82 +309,6 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream { concat_idents::concat_idents(ts) } -/// Used to specify the pinning information of the fields of a struct. -/// -/// This is somewhat similar in purpose as -/// [pin-project-lite](https://crates.io/crates/pin-project-lite). -/// Place this macro on a struct definition and then `#[pin]` in front of the attributes of each -/// field you want to structurally pin. -/// -/// This macro enables the use of the [`pin_init!`] macro. When pin-initializing a `struct`, -/// then `#[pin]` directs the type of initializer that is required. -/// -/// If your `struct` implements `Drop`, then you need to add `PinnedDrop` as arguments to this -/// macro, and change your `Drop` implementation to `PinnedDrop` annotated with -/// `#[`[`macro@pinned_drop`]`]`, since dropping pinned values requires extra care. -/// -/// # Examples -/// -/// ```rust,ignore -/// #[pin_data] -/// struct DriverData { -/// #[pin] -/// queue: Mutex<Vec<Command>>, -/// buf: Box<[u8; 1024 * 1024]>, -/// } -/// ``` -/// -/// ```rust,ignore -/// #[pin_data(PinnedDrop)] -/// struct DriverData { -/// #[pin] -/// queue: Mutex<Vec<Command>>, -/// buf: Box<[u8; 1024 * 1024]>, -/// raw_info: *mut Info, -/// } -/// -/// #[pinned_drop] -/// impl PinnedDrop for DriverData { -/// fn drop(self: Pin<&mut Self>) { -/// unsafe { bindings::destroy_info(self.raw_info) }; -/// } -/// } -/// ``` -/// -/// [`pin_init!`]: ../kernel/macro.pin_init.html -// ^ cannot use direct link, since `kernel` is not a dependency of `macros`. -#[proc_macro_attribute] -pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream { - pin_data::pin_data(inner, item) -} - -/// Used to implement `PinnedDrop` safely. -/// -/// Only works on structs that are annotated via `#[`[`macro@pin_data`]`]`. -/// -/// # Examples -/// -/// ```rust,ignore -/// #[pin_data(PinnedDrop)] -/// struct DriverData { -/// #[pin] -/// queue: Mutex<Vec<Command>>, -/// buf: Box<[u8; 1024 * 1024]>, -/// raw_info: *mut Info, -/// } -/// -/// #[pinned_drop] -/// impl PinnedDrop for DriverData { -/// fn drop(self: Pin<&mut Self>) { -/// unsafe { bindings::destroy_info(self.raw_info) }; -/// } -/// } -/// ``` -#[proc_macro_attribute] -pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { - pinned_drop::pinned_drop(args, input) -} - /// Paste identifiers together. /// /// Within the `paste!` macro, identifiers inside `[<` and `>]` are concatenated together to form a @@ -307,14 +318,27 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { /// literals (lifetimes and documentation strings are not supported). There is a difference in /// supported modifiers as well. /// -/// # Example -/// -/// ```ignore -/// use kernel::macro::paste; +/// # Examples /// +/// ``` +/// # const binder_driver_return_protocol_BR_OK: u32 = 0; +/// # const binder_driver_return_protocol_BR_ERROR: u32 = 1; +/// # const binder_driver_return_protocol_BR_TRANSACTION: u32 = 2; +/// # const binder_driver_return_protocol_BR_REPLY: u32 = 3; +/// # const binder_driver_return_protocol_BR_DEAD_REPLY: u32 = 4; +/// # const binder_driver_return_protocol_BR_TRANSACTION_COMPLETE: u32 = 5; +/// # const binder_driver_return_protocol_BR_INCREFS: u32 = 6; +/// # const binder_driver_return_protocol_BR_ACQUIRE: u32 = 7; +/// # const binder_driver_return_protocol_BR_RELEASE: u32 = 8; +/// # const binder_driver_return_protocol_BR_DECREFS: u32 = 9; +/// # const binder_driver_return_protocol_BR_NOOP: u32 = 10; +/// # const binder_driver_return_protocol_BR_SPAWN_LOOPER: u32 = 11; +/// # const binder_driver_return_protocol_BR_DEAD_BINDER: u32 = 12; +/// # const binder_driver_return_protocol_BR_CLEAR_DEATH_NOTIFICATION_DONE: u32 = 13; +/// # const binder_driver_return_protocol_BR_FAILED_REPLY: u32 = 14; /// macro_rules! pub_no_prefix { /// ($prefix:ident, $($newname:ident),+) => { -/// paste! { +/// ::kernel::macros::paste! { /// $(pub(crate) const $newname: u32 = [<$prefix $newname>];)+ /// } /// }; @@ -353,13 +377,26 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { /// * `lower`: change the identifier to lower case. /// * `upper`: change the identifier to upper case. /// -/// ```ignore -/// use kernel::macro::paste; -/// +/// ``` +/// # const binder_driver_return_protocol_BR_OK: u32 = 0; +/// # const binder_driver_return_protocol_BR_ERROR: u32 = 1; +/// # const binder_driver_return_protocol_BR_TRANSACTION: u32 = 2; +/// # const binder_driver_return_protocol_BR_REPLY: u32 = 3; +/// # const binder_driver_return_protocol_BR_DEAD_REPLY: u32 = 4; +/// # const binder_driver_return_protocol_BR_TRANSACTION_COMPLETE: u32 = 5; +/// # const binder_driver_return_protocol_BR_INCREFS: u32 = 6; +/// # const binder_driver_return_protocol_BR_ACQUIRE: u32 = 7; +/// # const binder_driver_return_protocol_BR_RELEASE: u32 = 8; +/// # const binder_driver_return_protocol_BR_DECREFS: u32 = 9; +/// # const binder_driver_return_protocol_BR_NOOP: u32 = 10; +/// # const binder_driver_return_protocol_BR_SPAWN_LOOPER: u32 = 11; +/// # const binder_driver_return_protocol_BR_DEAD_BINDER: u32 = 12; +/// # const binder_driver_return_protocol_BR_CLEAR_DEATH_NOTIFICATION_DONE: u32 = 13; +/// # const binder_driver_return_protocol_BR_FAILED_REPLY: u32 = 14; /// macro_rules! pub_no_prefix { /// ($prefix:ident, $($newname:ident),+) => { -/// kernel::macros::paste! { -/// $(pub(crate) const fn [<$newname:lower:span>]: u32 = [<$prefix $newname:span>];)+ +/// ::kernel::macros::paste! { +/// $(pub(crate) const fn [<$newname:lower:span>]() -> u32 { [<$prefix $newname:span>] })+ /// } /// }; /// } @@ -390,10 +427,10 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { /// /// Literals can also be concatenated with other identifiers: /// -/// ```ignore +/// ``` /// macro_rules! create_numbered_fn { /// ($name:literal, $val:literal) => { -/// kernel::macros::paste! { +/// ::kernel::macros::paste! { /// fn [<some_ $name _fn $val>]() -> u32 { $val } /// } /// }; @@ -412,21 +449,29 @@ pub fn paste(input: TokenStream) -> TokenStream { tokens.into_iter().collect() } -/// Derives the [`Zeroable`] trait for the given struct. +/// Registers a KUnit test suite and its test cases using a user-space like syntax. /// -/// This can only be used for structs where every field implements the [`Zeroable`] trait. +/// This macro should be used on modules. If `CONFIG_KUNIT` (in `.config`) is `n`, the target module +/// is ignored. /// /// # Examples /// -/// ```rust,ignore -/// #[derive(Zeroable)] -/// pub struct DriverData { -/// id: i64, -/// buf_ptr: *mut u8, -/// len: usize, +/// ```ignore +/// # use kernel::prelude::*; +/// #[kunit_tests(kunit_test_suit_name)] +/// mod tests { +/// #[test] +/// fn foo() { +/// assert_eq!(1, 1); +/// } +/// +/// #[test] +/// fn bar() { +/// assert_eq!(2, 2); +/// } /// } /// ``` -#[proc_macro_derive(Zeroable)] -pub fn derive_zeroable(input: TokenStream) -> TokenStream { - zeroable::derive(input) +#[proc_macro_attribute] +pub fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream { + kunit::kunit_tests(attr, ts) } |
