diff --git a/init/Kconfig b/init/Kconfig index efde2275da532e..6a9047318cb38f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2059,6 +2059,7 @@ config RUST depends on ARM64 || CPU_32v6 || CPU_32v6K || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64 || RISCV depends on !MODVERSIONS depends on !GCC_PLUGIN_RANDSTRUCT + select CONSTRUCTORS default n help Enables Rust support in the kernel. diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 840099f384b356..eb2e2d7ef8475f 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -338,7 +338,7 @@ where /// ``` #[macro_export] macro_rules! c_str { - ($str:literal) => {{ + ($str:expr) => {{ const S: &str = concat!($str, "\0"); const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes()); C diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index 32709777bbe5fc..0d6eb301a2bf49 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -48,7 +48,7 @@ impl CondVar { /// # Safety /// /// The caller must call `CondVar::init` before using the conditional variable. - pub unsafe fn new() -> Self { + pub const unsafe fn new() -> Self { Self { wait_list: Opaque::uninit(), _pin: PhantomPinned, diff --git a/rust/kernel/sync/mod.rs b/rust/kernel/sync/mod.rs index 960d5cd1aa198e..82bfec652dfcb2 100644 --- a/rust/kernel/sync/mod.rs +++ b/rust/kernel/sync/mod.rs @@ -49,7 +49,7 @@ pub use spinlock::SpinLock; #[doc(hidden)] #[macro_export] macro_rules! init_with_lockdep { - ($obj:expr, $name:literal) => {{ + ($obj:expr, $name:expr) => {{ static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> = core::mem::MaybeUninit::uninit(); static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> = @@ -87,6 +87,69 @@ pub trait NeedsLockClass { ); } +/// Automatically initialises static instances of synchronisation primitives. +/// +/// The syntax resembles that of regular static variables, except that the value assigned is that +/// of the protected type (if one exists). In the examples below, all primitives except for +/// [`CondVar`] require the inner value to be supplied. +/// +/// # Examples +/// +/// ```ignore +/// # use kernel::{init_static_sync, sync::{CondVar, Mutex, RevocableMutex, SpinLock}}; +/// struct Test { +/// a: u32, +/// b: u32, +/// } +/// +/// init_static_sync! { +/// static A: Mutex = Test { a: 10, b: 20 }; +/// +/// /// Documentation for `B`. +/// pub static B: Mutex = 0; +/// +/// pub(crate) static C: SpinLock = Test { a: 10, b: 20 }; +/// static D: CondVar; +/// +/// static E: RevocableMutex = Test { a: 30, b: 40 }; +/// } +/// ``` +#[macro_export] +macro_rules! init_static_sync { + ($($(#[$outer:meta])* $v:vis static $id:ident : $t:ty $(= $value:expr)?;)*) => { + $( + $(#[$outer])* + $v static $id: $t = { + #[link_section = ".ctors"] + #[used] + static TMP: extern "C" fn() = { + extern "C" fn constructor() { + // SAFETY: This locally-defined function is only called from a constructor, + // which guarantees that `$id` is not accessible from other threads + // concurrently. + #[allow(clippy::cast_ref_to_mut)] + let mutable = unsafe { &mut *(&$id as *const _ as *mut $t) }; + // SAFETY: It's a shared static, so it cannot move. + let pinned = unsafe { core::pin::Pin::new_unchecked(mutable) }; + $crate::init_with_lockdep!(pinned, stringify!($id)); + } + constructor + }; + $crate::init_static_sync!(@call_new $t, $($value)?) + }; + )* + }; + (@call_new $t:ty, $value:expr) => {{ + let v = $value; + // SAFETY: the initialisation function is called by the constructor above. + unsafe { <$t>::new(v) } + }}; + (@call_new $t:ty,) => { + // SAFETY: the initialisation function is called by the constructor above. + unsafe { <$t>::new() } + }; +} + /// Reschedules the caller's task if needed. pub fn cond_resched() -> bool { // SAFETY: No arguments, reschedules `current` if needed. diff --git a/rust/kernel/sync/mutex.rs b/rust/kernel/sync/mutex.rs index eacdbc3c19ac5f..5400b109cc11e5 100644 --- a/rust/kernel/sync/mutex.rs +++ b/rust/kernel/sync/mutex.rs @@ -53,7 +53,7 @@ impl Mutex { /// # Safety /// /// The caller must call [`Mutex::init_lock`] before using the mutex. - pub unsafe fn new(t: T) -> Self { + pub const unsafe fn new(t: T) -> Self { Self { mutex: Opaque::uninit(), data: UnsafeCell::new(t), diff --git a/rust/kernel/sync/revocable_mutex.rs b/rust/kernel/sync/revocable_mutex.rs index 208104625ab1e1..d2d56fdfc4fe12 100644 --- a/rust/kernel/sync/revocable_mutex.rs +++ b/rust/kernel/sync/revocable_mutex.rs @@ -80,7 +80,7 @@ impl RevocableMutex { /// # Safety /// /// The caller must call [`RevocableMutex::init`] before using the revocable mutex. - pub unsafe fn new(data: T) -> Self { + pub const unsafe fn new(data: T) -> Self { Self { // SAFETY: The safety requirements of this function require that `RevocableMutex::init` // be called before the returned object can be used. Mutex initialisation is called diff --git a/rust/kernel/sync/spinlock.rs b/rust/kernel/sync/spinlock.rs index 8a1f87ad5c094d..07c1368408c722 100644 --- a/rust/kernel/sync/spinlock.rs +++ b/rust/kernel/sync/spinlock.rs @@ -96,7 +96,7 @@ impl SpinLock { /// # Safety /// /// The caller must call [`SpinLock::init_lock`] before using the spinlock. - pub unsafe fn new(t: T) -> Self { + pub const unsafe fn new(t: T) -> Self { Self { spin_lock: Opaque::uninit(), data: UnsafeCell::new(t), diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 64f11005b55335..61186fc89049bd 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -283,7 +283,7 @@ impl Opaque { } /// Creates an uninitialised value. - pub fn uninit() -> Self { + pub const fn uninit() -> Self { Self(MaybeUninit::uninit()) }