Skip to main content

kernel_api/
modules.rs

1//! Kernel modules.
2//!
3//! # Examples
4//!
5//! ```
6//! use kernel_api::modules::{kernel_module, Module};
7//! use kernel_api::sync::OnceLock;
8//!
9//! struct MyModuleContext {
10//!     // ...
11//! # foo: i32,
12//! }
13//!
14//! static CONTEXT: OnceLock<MyModuleContext> = OnceLock::new();
15//!
16//! kernel_module! {
17//!     type: MyModuleContext,
18//!     name: "My Custom Module",
19//!     author: "Popcorn Contributors",
20//!     license: "MPL-2.0",
21//! }
22//!
23//! impl Module for MyModuleContext {
24//!     fn early_init() -> Result<(), &'static str> {
25//!          debug!("early init of `My Custom Module`");
26//!          Ok(())
27//!     }
28//!
29//!     fn late_init() -> Result<(), &'static str> {
30//!          debug!("late init of `My Custom Module`");
31//!          // initialise context
32//!          CONTEXT.get_or_init(Self::new);
33//!          Ok(())
34//!     }
35//! }
36//!
37//! impl MyModuleContext {
38//!     fn new() -> Self {
39//!         // ...
40//! #       Self { foo: 5 }
41//!     }
42//! }
43//! ```
44
45/// Registers a kernel module with the kernel.
46///
47/// The `type` argument should be a type implementing the [`Module`] trait.
48///
49/// Additionally, it also takes the following arguments in order:
50/// - `name` - a user facing name for the module
51/// - `description` (optional) - a user facing description of the module
52/// - `author` (optional) - the author of the module
53/// - `license` - An SPDX license identifier (currently only `MPL-*` is accepted)
54///
55/// # Examples
56///
57/// See the [module-level documentation](self).
58#[expect(rustdoc::missing_doc_code_examples, reason = "documented at module level")]
59#[macro_export]
60macro_rules! kernel_module {
61    (
62	    type: $ty:ty,
63	    name: $name:literal,
64	    $(description: $description:literal,)?
65	    $(author: $author:literal,)?
66	    license: $license:tt$(,)?
67    ) => {
68	    const _: () = {
69		    $crate::kernel_module_license!(@license $license);
70		    const fn __assert_module_implements_module<T: $crate::modules::Module>() {}
71		    __assert_module_implements_module::<$ty>();
72	    };
73    };
74}
75
76#[macro_export]
77#[doc(hidden)]
78macro_rules! kernel_module_license {
79	(@license "MPL-1.0") => {};
80	(@license "MPL-1.1") => {};
81	(@license "MPL-2.0") => {};
82}
83
84/// The top level trait for a kernel module.
85///
86/// This is to be implemented on a ZST to allow the module to hook into
87/// various points during kernel boot.
88///
89/// # Examples
90///
91/// See the [module-level documentation](self).
92#[expect(rustdoc::missing_doc_code_examples, reason = "documented at module level")]
93pub trait Module {
94    /// Called immediately upon kernel start.
95    ///
96    /// At this point many kernel features are unusable, such as
97    /// threading, async tasks, and memory allocation.
98    #[expect(clippy::missing_errors_doc, reason = "errors depend on implementor")]
99    #[expect(rustdoc::missing_doc_code_examples, reason = "not called by end users")]
100    fn early_init() -> Result<(), &'static str> { Ok(()) }
101
102    /// Called once the kernel is ready to start userspace applications.
103    #[expect(clippy::missing_errors_doc, reason = "errors depend on implementor")]
104    #[expect(rustdoc::missing_doc_code_examples, reason = "not called by end users")]
105    fn late_init() -> Result<(), &'static str> { Ok(()) }
106}