diff options
Diffstat (limited to 'rust/kernel')
-rw-r--r-- | rust/kernel/allocator.rs | 84 | ||||
-rw-r--r-- | rust/kernel/init.rs | 646 | ||||
-rw-r--r-- | rust/kernel/init/__internal.rs | 39 | ||||
-rw-r--r-- | rust/kernel/init/macros.rs | 519 | ||||
-rw-r--r-- | rust/kernel/lib.rs | 3 | ||||
-rw-r--r-- | rust/kernel/prelude.rs | 2 | ||||
-rw-r--r-- | rust/kernel/sync/lock.rs | 6 | ||||
-rw-r--r-- | rust/kernel/types.rs | 21 |
8 files changed, 803 insertions, 517 deletions
diff --git a/rust/kernel/allocator.rs b/rust/kernel/allocator.rs index 9363b527be66..a8f3d5be1af1 100644 --- a/rust/kernel/allocator.rs +++ b/rust/kernel/allocator.rs @@ -41,9 +41,9 @@ unsafe fn krealloc_aligned(ptr: *mut u8, new_layout: Layout, flags: bindings::gf unsafe impl GlobalAlloc for KernelAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - // `krealloc()` is used instead of `kmalloc()` because the latter is - // an inline function and cannot be bound to as a result. - unsafe { bindings::krealloc(ptr::null(), layout.size(), bindings::GFP_KERNEL) as *mut u8 } + // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety + // requirement. + unsafe { krealloc_aligned(ptr::null_mut(), layout, bindings::GFP_KERNEL) } } unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { @@ -51,58 +51,38 @@ unsafe impl GlobalAlloc for KernelAllocator { bindings::kfree(ptr as *const core::ffi::c_void); } } -} - -#[global_allocator] -static ALLOCATOR: KernelAllocator = KernelAllocator; - -// `rustc` only generates these for some crate types. Even then, we would need -// to extract the object file that has them from the archive. For the moment, -// let's generate them ourselves instead. -// -// Note: Although these are *safe* functions, they are called by the compiler -// with parameters that obey the same `GlobalAlloc` function safety -// requirements: size and align should form a valid layout, and size is -// greater than 0. -// -// Note that `#[no_mangle]` implies exported too, nowadays. -#[no_mangle] -fn __rust_alloc(size: usize, align: usize) -> *mut u8 { - // SAFETY: See assumption above. - let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; - // SAFETY: `ptr::null_mut()` is null, per assumption above the size of `layout` is greater - // than 0. - unsafe { krealloc_aligned(ptr::null_mut(), layout, bindings::GFP_KERNEL) } -} + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + // SAFETY: + // - `new_size`, when rounded up to the nearest multiple of `layout.align()`, will not + // overflow `isize` by the function safety requirement. + // - `layout.align()` is a proper alignment (i.e. not zero and must be a power of two). + let layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; + + // SAFETY: + // - `ptr` is either null or a pointer allocated by this allocator by the function safety + // requirement. + // - the size of `layout` is not zero because `new_size` is not zero by the function safety + // requirement. + unsafe { krealloc_aligned(ptr, layout, bindings::GFP_KERNEL) } + } -#[no_mangle] -fn __rust_dealloc(ptr: *mut u8, _size: usize, _align: usize) { - unsafe { bindings::kfree(ptr as *const core::ffi::c_void) }; + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // SAFETY: `ptr::null_mut()` is null and `layout` has a non-zero size by the function safety + // requirement. + unsafe { + krealloc_aligned( + ptr::null_mut(), + layout, + bindings::GFP_KERNEL | bindings::__GFP_ZERO, + ) + } + } } -#[no_mangle] -fn __rust_realloc(ptr: *mut u8, _old_size: usize, align: usize, new_size: usize) -> *mut u8 { - // SAFETY: See assumption above. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, align) }; - - // SAFETY: Per assumption above, `ptr` is allocated by `__rust_*` before, and the size of - // `new_layout` is greater than 0. - unsafe { krealloc_aligned(ptr, new_layout, bindings::GFP_KERNEL) } -} +#[global_allocator] +static ALLOCATOR: KernelAllocator = KernelAllocator; +// See <https://github.com/rust-lang/rust/pull/86844>. #[no_mangle] -fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8 { - // SAFETY: See assumption above. - let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; - - // SAFETY: `ptr::null_mut()` is null, per assumption above the size of `layout` is greater - // than 0. - unsafe { - krealloc_aligned( - ptr::null_mut(), - layout, - bindings::GFP_KERNEL | bindings::__GFP_ZERO, - ) - } -} +static __rust_no_alloc_shim_is_unstable: u8 = 0; diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index e05563aad2ed..4ebb6f23fc2e 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -212,11 +212,12 @@ use crate::{ error::{self, Error}, sync::UniqueArc, + types::{Opaque, ScopeGuard}, }; use alloc::boxed::Box; use core::{ alloc::AllocError, - cell::Cell, + cell::UnsafeCell, convert::Infallible, marker::PhantomData, mem::MaybeUninit, @@ -518,13 +519,17 @@ macro_rules! stack_try_pin_init { /// - Fields that you want to initialize in-place have to use `<-` instead of `:`. /// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`] /// pointer named `this` inside of the initializer. +/// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the +/// struct, this initializes every field with 0 and then runs all initializers specified in the +/// body. This can only be done if [`Zeroable`] is implemented for the struct. /// /// For instance: /// /// ```rust -/// # use kernel::{macros::pin_data, pin_init}; +/// # use kernel::{macros::{Zeroable, pin_data}, pin_init}; /// # use core::{ptr::addr_of_mut, marker::PhantomPinned}; /// #[pin_data] +/// #[derive(Zeroable)] /// struct Buf { /// // `ptr` points into `buf`. /// ptr: *mut u8, @@ -537,6 +542,10 @@ macro_rules! stack_try_pin_init { /// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() }, /// pin: PhantomPinned, /// }); +/// pin_init!(Buf { +/// buf: [1; 64], +/// ..Zeroable::zeroed() +/// }); /// ``` /// /// [`try_pin_init!`]: kernel::try_pin_init @@ -548,11 +557,15 @@ macro_rules! pin_init { ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }) => { - $crate::try_pin_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)?), @fields($($fields)*), @error(::core::convert::Infallible), + @data(PinData, use_data), + @has_data(HasPinData, __pin_data), + @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), ) }; } @@ -601,205 +614,31 @@ macro_rules! try_pin_init { ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }) => { - $crate::try_pin_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)? ), @fields($($fields)*), @error($crate::error::Error), + @data(PinData, use_data), + @has_data(HasPinData, __pin_data), + @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), ) }; ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }? $err:ty) => { - $crate::try_pin_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)? ), @fields($($fields)*), @error($err), + @data(PinData, use_data), + @has_data(HasPinData, __pin_data), + @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), ) }; - ( - @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), - @fields($($fields:tt)*), - @error($err:ty), - ) => {{ - // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return - // type and shadow it later when we insert the arbitrary user code. That way there will be - // no possibility of returning without `unsafe`. - struct __InitOk; - // Get the pin data from the supplied type. - let data = unsafe { - use $crate::init::__internal::HasPinData; - $t$(::<$($generics),*>)?::__pin_data() - }; - // Ensure that `data` really is of type `PinData` and help with type inference: - let init = $crate::init::__internal::PinData::make_closure::<_, __InitOk, $err>( - data, - move |slot| { - { - // Shadow the structure so it cannot be used to return early. - struct __InitOk; - // Create the `this` so it can be referenced by the user inside of the - // expressions creating the individual fields. - $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? - // Initialize every field. - $crate::try_pin_init!(init_slot: - @data(data), - @slot(slot), - @munch_fields($($fields)*,), - ); - // We use unreachable code to ensure that all fields have been mentioned exactly - // once, this struct initializer will still be type-checked and complain with a - // very natural error message if a field is forgotten/mentioned more than once. - #[allow(unreachable_code, clippy::diverging_sub_expression)] - if false { - $crate::try_pin_init!(make_initializer: - @slot(slot), - @type_name($t), - @munch_fields($($fields)*,), - @acc(), - ); - } - // Forget all guards, since initialization was a success. - $crate::try_pin_init!(forget_guards: - @munch_fields($($fields)*,), - ); - } - Ok(__InitOk) - } - ); - let init = move |slot| -> ::core::result::Result<(), $err> { - init(slot).map(|__InitOk| ()) - }; - let init = unsafe { $crate::init::pin_init_from_closure::<_, $err>(init) }; - init - }}; - (init_slot: - @data($data:ident), - @slot($slot:ident), - @munch_fields($(,)?), - ) => { - // Endpoint of munching, no fields are left. - }; - (init_slot: - @data($data:ident), - @slot($slot:ident), - // In-place initialization syntax. - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) => { - let $field = $val; - // Call the initializer. - // - // SAFETY: `slot` is valid, because we are inside of an initializer closure, we - // return when an error/panic occurs. - // We also use the `data` to require the correct trait (`Init` or `PinInit`) for `$field`. - unsafe { $data.$field(::core::ptr::addr_of_mut!((*$slot).$field), $field)? }; - // Create the drop guard. - // - // We only give access to `&DropGuard`, so it cannot be forgotten via safe code. - // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; - - $crate::try_pin_init!(init_slot: - @data($data), - @slot($slot), - @munch_fields($($rest)*), - ); - }; - (init_slot: - @data($data:ident), - @slot($slot:ident), - // Direct value init, this is safe for every field. - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) => { - $(let $field = $val;)? - // Initialize the field. - // - // SAFETY: The memory at `slot` is uninitialized. - unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) }; - // Create the drop guard: - // - // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. - // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; - - $crate::try_pin_init!(init_slot: - @data($data), - @slot($slot), - @munch_fields($($rest)*), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($(,)?), - @acc($($acc:tt)*), - ) => { - // Endpoint, nothing more to munch, create the initializer. - // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to - // get the correct type inference here: - unsafe { - ::core::ptr::write($slot, $t { - $($acc)* - }); - } - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - @acc($($acc:tt)*), - ) => { - $crate::try_pin_init!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)* $field: ::core::panic!(),), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - @acc($($acc:tt)*), - ) => { - $crate::try_pin_init!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)* $field: ::core::panic!(),), - ); - }; - (forget_guards: - @munch_fields($(,)?), - ) => { - // Munching finished. - }; - (forget_guards: - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::try_pin_init!(forget_guards: - @munch_fields($($rest)*), - ); - }; - (forget_guards: - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::try_pin_init!(forget_guards: - @munch_fields($($rest)*), - ); - }; } /// Construct an in-place initializer for `struct`s. @@ -824,11 +663,15 @@ macro_rules! init { ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }) => { - $crate::try_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)?), @fields($($fields)*), @error(::core::convert::Infallible), + @data(InitData, /*no use_data*/), + @has_data(HasInitData, __init_data), + @construct_closure(init_from_closure), + @munch_fields($($fields)*), ) } } @@ -871,199 +714,31 @@ macro_rules! try_init { ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }) => { - $crate::try_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)?), @fields($($fields)*), @error($crate::error::Error), + @data(InitData, /*no use_data*/), + @has_data(HasInitData, __init_data), + @construct_closure(init_from_closure), + @munch_fields($($fields)*), ) }; ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }? $err:ty) => { - $crate::try_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)?), @fields($($fields)*), @error($err), + @data(InitData, /*no use_data*/), + @has_data(HasInitData, __init_data), + @construct_closure(init_from_closure), + @munch_fields($($fields)*), ) }; - ( - @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), - @fields($($fields:tt)*), - @error($err:ty), - ) => {{ - // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return - // type and shadow it later when we insert the arbitrary user code. That way there will be - // no possibility of returning without `unsafe`. - struct __InitOk; - // Get the init data from the supplied type. - let data = unsafe { - use $crate::init::__internal::HasInitData; - $t$(::<$($generics),*>)?::__init_data() - }; - // Ensure that `data` really is of type `InitData` and help with type inference: - let init = $crate::init::__internal::InitData::make_closure::<_, __InitOk, $err>( - data, - move |slot| { - { - // Shadow the structure so it cannot be used to return early. - struct __InitOk; - // Create the `this` so it can be referenced by the user inside of the - // expressions creating the individual fields. - $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? - // Initialize every field. - $crate::try_init!(init_slot: - @slot(slot), - @munch_fields($($fields)*,), - ); - // We use unreachable code to ensure that all fields have been mentioned exactly - // once, this struct initializer will still be type-checked and complain with a - // very natural error message if a field is forgotten/mentioned more than once. - #[allow(unreachable_code, clippy::diverging_sub_expression)] - if false { - $crate::try_init!(make_initializer: - @slot(slot), - @type_name($t), - @munch_fields($($fields)*,), - @acc(), - ); - } - // Forget all guards, since initialization was a success. - $crate::try_init!(forget_guards: - @munch_fields($($fields)*,), - ); - } - Ok(__InitOk) - } - ); - let init = move |slot| -> ::core::result::Result<(), $err> { - init(slot).map(|__InitOk| ()) - }; - let init = unsafe { $crate::init::init_from_closure::<_, $err>(init) }; - init - }}; - (init_slot: - @slot($slot:ident), - @munch_fields( $(,)?), - ) => { - // Endpoint of munching, no fields are left. - }; - (init_slot: - @slot($slot:ident), - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) => { - let $field = $val; - // Call the initializer. - // - // SAFETY: `slot` is valid, because we are inside of an initializer closure, we - // return when an error/panic occurs. - unsafe { - $crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))?; - } - // Create the drop guard. - // - // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. - // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; - - $crate::try_init!(init_slot: - @slot($slot), - @munch_fields($($rest)*), - ); - }; - (init_slot: - @slot($slot:ident), - // Direct value init. - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) => { - $(let $field = $val;)? - // Call the initializer. - // - // SAFETY: The memory at `slot` is uninitialized. - unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) }; - // Create the drop guard. - // - // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. - // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; - - $crate::try_init!(init_slot: - @slot($slot), - @munch_fields($($rest)*), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields( $(,)?), - @acc($($acc:tt)*), - ) => { - // Endpoint, nothing more to munch, create the initializer. - // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to - // get the correct type inference here: - unsafe { - ::core::ptr::write($slot, $t { - $($acc)* - }); - } - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - @acc($($acc:tt)*), - ) => { - $crate::try_init!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)*$field: ::core::panic!(),), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - @acc($($acc:tt)*), - ) => { - $crate::try_init!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)*$field: ::core::panic!(),), - ); - }; - (forget_guards: - @munch_fields($(,)?), - ) => { - // Munching finished. - }; - (forget_guards: - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::try_init!(forget_guards: - @munch_fields($($rest)*), - ); - }; - (forget_guards: - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::try_init!(forget_guards: - @munch_fields($($rest)*), - ); - }; } /// A pin-initializer for the type `T`. @@ -1100,6 +775,79 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { /// deallocate. /// - `slot` will not move until it is dropped, i.e. it will be pinned. unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>; + + /// First initializes the value using `self` then calls the function `f` with the initialized + /// value. + /// + /// If `f` returns an error the value is dropped and the initializer will forward the error. + /// + /// # Examples + /// + /// ```rust + /// # #![allow(clippy::disallowed_names)] + /// use kernel::{types::Opaque, init::pin_init_from_closure}; + /// #[repr(C)] + /// struct RawFoo([u8; 16]); + /// extern { + /// fn init_foo(_: *mut RawFoo); + /// } + /// + /// #[pin_data] + /// struct Foo { + /// #[pin] + /// raw: Opaque<RawFoo>, + /// } + /// + /// impl Foo { + /// fn setup(self: Pin<&mut Self>) { + /// pr_info!("Setting up foo"); + /// } + /// } + /// + /// let foo = pin_init!(Foo { + /// raw <- unsafe { + /// Opaque::ffi_init(|s| { + /// init_foo(s); + /// }) + /// }, + /// }).pin_chain(|foo| { + /// foo.setup(); + /// Ok(()) + /// }); + /// ``` + fn pin_chain<F>(self, f: F) -> ChainPinInit<Self, F, T, E> + where + F: FnOnce(Pin<&mut T>) -> Result<(), E>, + { + ChainPinInit(self, f, PhantomData) + } +} + +/// An initializer returned by [`PinInit::pin_chain`]. +pub struct ChainPinInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, Box<T>)>); + +// SAFETY: The `__pinned_init` function is implemented such that it +// - returns `Ok(())` on successful initialization, +// - returns `Err(err)` on error and in this case `slot` will be dropped. +// - considers `slot` pinned. +unsafe impl<T: ?Sized, E, I, F> PinInit<T, E> for ChainPinInit<I, F, T, E> +where + I: PinInit<T, E>, + F: FnOnce(Pin<&mut T>) -> Result<(), E>, +{ + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: All requirements fulfilled since this function is `__pinned_init`. + unsafe { self.0.__pinned_init(slot)? }; + // SAFETY: The above call initialized `slot` and we still have unique access. + let val = unsafe { &mut *slot }; + // SAFETY: `slot` is considered pinned. + let val = unsafe { Pin::new_unchecked(val) }; + (self.1)(val).map_err(|e| { + // SAFETY: `slot` was initialized above. + unsafe { core::ptr::drop_in_place(slot) }; + e + }) + } } /// An initializer for `T`. @@ -1132,7 +880,7 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { /// /// [`Arc<T>`]: crate::sync::Arc #[must_use = "An initializer must be used in order to create its value."] -pub unsafe trait Init<T: ?Sized, E = Infallible>: Sized { +pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> { /// Initializes `slot`. /// /// # Safety @@ -1141,16 +889,73 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: Sized { /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to /// deallocate. unsafe fn __init(self, slot: *mut T) -> Result<(), E>; + + /// First initializes the value using `self` then calls the function `f` with the initialized + /// value. + /// + /// If `f` returns an error the value is dropped and the initializer will forward the error. + /// + /// # Examples + /// + /// ```rust + /// # #![allow(clippy::disallowed_names)] + /// use kernel::{types::Opaque, init::{self, init_from_closure}}; + /// struct Foo { + /// buf: [u8; 1_000_000], + /// } + /// + /// impl Foo { + /// fn setup(&mut self) { + /// pr_info!("Setting up foo"); + /// } + /// } + /// + /// let foo = init!(Foo { + /// buf <- init::zeroed() + /// }).chain(|foo| { + /// foo.setup(); + /// Ok(()) + /// }); + /// ``` + fn chain<F>(self, f: F) -> ChainInit<Self, F, T, E> + where + F: FnOnce(&mut T) -> Result<(), E>, + { + ChainInit(self, f, PhantomData) + } } -// SAFETY: Every in-place initializer can also be used as a pin-initializer. -unsafe impl<T: ?Sized, E, I> PinInit<T, E> for I +/// An initializer returned by [`Init::chain`]. +pub struct ChainInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, Box<T>)>); + +// SAFETY: The `__init` function is implemented such that it +// - returns `Ok(())` on successful initialization, +// - returns `Err(err)` on error and in this case `slot` will be dropped. +unsafe impl<T: ?Sized, E, I, F> Init<T, E> for ChainInit<I, F, T, E> where I: Init<T, E>, + F: FnOnce(&mut T) -> Result<(), E>, +{ + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: All requirements fulfilled since this function is `__init`. + unsafe { self.0.__pinned_init(slot)? }; + // SAFETY: The above call initialized `slot` and we still have unique access. + (self.1)(unsafe { &mut *slot }).map_err(|e| { + // SAFETY: `slot` was initialized above. + unsafe { core::ptr::drop_in_place(slot) }; + e + }) + } +} + +// SAFETY: `__pinned_init` behaves exactly the same as `__init`. +unsafe impl<T: ?Sized, E, I, F> PinInit<T, E> for ChainInit<I, F, T, E> +where + I: Init<T, E>, + F: FnOnce(&mut T) -> Result<(), E>, { unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: `__init` meets the same requirements as `__pinned_init`, except that it does not - // require `slot` to not move after init. + // SAFETY: `__init` has less strict requirements compared to `__pinned_init`. unsafe { self.__init(slot) } } } @@ -1202,6 +1007,93 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> { unsafe { init_from_closure(|_| Ok(())) } } +/// Initializes an array by initializing each element via the provided initializer. +/// +/// # Examples +/// +/// ```rust +/// use kernel::{error::Error, init::init_array_from_fn}; +/// let array: Box<[usize; 1_000]>= Box::init::<Error>(init_array_from_fn(|i| i)).unwrap(); +/// assert_eq!(array.len(), 1_000); +/// ``` +pub fn init_array_from_fn<I, const N: usize, T, E>( + mut make_init: impl FnMut(usize) -> I, +) -> impl Init<[T; N], E> +where + I: Init<T, E>, +{ + let init = move |slot: *mut [T; N]| { + let slot = slot.cast::<T>(); + // Counts the number of initialized elements and when dropped drops that many elements from + // `slot`. + let mut init_count = ScopeGuard::new_with_data(0, |i| { + // We now free every element that has been initialized before: + // SAFETY: The loop initialized exactly the values from 0..i and since we + // return `Err` below, the caller will consider the memory at `slot` as + // uninitialized. + unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) }; + }); + for i in 0..N { + let init = make_init(i); + // SAFETY: Since 0 <= `i` < N, it is still in bounds of `[T; N]`. + let ptr = unsafe { slot.add(i) }; + // SAFETY: The pointer is derived from `slot` and thus satisfies the `__init` + // requirements. + unsafe { init.__init(ptr) }?; + *init_count += 1; + } + init_count.dismiss(); + Ok(()) + }; + // SAFETY: The initializer above initializes every element of the array. On failure it drops + // any initialized elements and returns `Err`. + unsafe { init_from_closure(init) } +} + +/// Initializes an array by initializing each element via the provided initializer. +/// +/// # Examples +/// +/// ```rust +/// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex}; +/// let array: Arc<[Mutex<usize>; 1_000]>= +/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i))).unwrap(); +/// assert_eq!(array.len(), 1_000); +/// ``` +pub fn pin_init_array_from_fn<I, const N: usize, T, E>( + mut make_init: impl FnMut(usize) -> I, +) -> impl PinInit<[T; N], E> +where + I: PinInit<T, E>, +{ + let init = move |slot: *mut [T; N]| { + let slot = slot.cast::<T>(); + // Counts the number of initialized elements and when dropped drops that many elements from + // `slot`. + let mut init_count = ScopeGuard::new_with_data(0, |i| { + // We now free every element that has been initialized before: + // SAFETY: The loop initialized exactly the values from 0..i and since we + // return `Err` below, the caller will consider the memory at `slot` as + // uninitialized. + unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) }; + }); + for i in 0..N { + let init = make_init(i); + // SAFETY: Since 0 <= `i` < N, it is still in bounds of `[T; N]`. + let ptr = unsafe { slot.add(i) }; + // SAFETY: The pointer is derived from `slot` and thus satisfies the `__init` + // requirements. + unsafe { init.__pinned_init(ptr) }?; + *init_count += 1; + } + init_count.dismiss(); + Ok(()) + }; + // SAFETY: The initializer above initializes every element of the array. On failure it drops + // any initialized elements and returns `Err`. + unsafe { pin_init_from_closure(init) } +} + // SAFETY: Every type can be initialized by-value. unsafe impl<T, E> Init<T, E> for T { unsafe fn __init(self, slot: *mut T) -> Result<(), E> { @@ -1210,6 +1102,13 @@ unsafe impl<T, E> Init<T, E> for T { } } +// SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`. +unsafe impl<T, E> PinInit<T, E> for T { + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + unsafe { self.__init(slot) } + } +} + /// Smart pointer that can initialize memory in-place. pub trait InPlaceInit<T>: Sized { /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this @@ -1398,6 +1297,11 @@ impl_zeroable! { // SAFETY: Type is allowed to take any value, including all zeros. {<T>} MaybeUninit<T>, + // SAFETY: Type is allowed to take any value, including all zeros. + {<T>} Opaque<T>, + + // SAFETY: `T: Zeroable` and `UnsafeCell` is `repr(transparent)`. + {<T: ?Sized + Zeroable>} UnsafeCell<T>, // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee). Option<NonZeroU8>, Option<NonZeroU16>, Option<NonZeroU32>, Option<NonZeroU64>, diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 44751fb62b51..db3372619ecd 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -13,7 +13,7 @@ use super::*; /// /// [nomicon]: https://doc.rust-lang.org/nomicon/subtyping.html /// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns -type Invariant<T> = PhantomData<fn(*mut T) -> *mut T>; +pub(super) type Invariant<T> = PhantomData<fn(*mut T) -> *mut T>; /// This is the module-internal type implementing `PinInit` and `Init`. It is unsafe to create this /// type, since the closure needs to fulfill the same safety requirement as the @@ -32,6 +32,18 @@ where } } +// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the +// `__pinned_init` invariants. +unsafe impl<T: ?Sized, F, E> PinInit<T, E> for InitClosure<F, T, E> +where + F: FnOnce(*mut T) -> Result<(), E>, +{ + #[inline] + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + (self.0)(slot) + } +} + /// This trait is only implemented via the `#[pin_data]` proc-macro. It is used to facilitate /// the pin projections within the initializers. /// @@ -174,7 +186,6 @@ impl<T> StackInit<T> { /// Can be forgotten to prevent the drop. pub struct DropGuard<T: ?Sized> { ptr: *mut T, - do_drop: Cell<bool>, } impl<T: ?Sized> DropGuard<T> { @@ -190,32 +201,16 @@ impl<T: ?Sized> DropGuard<T> { /// - will not be dropped by any other means. #[inline] pub unsafe fn new(ptr: *mut T) -> Self { - Self { - ptr, - do_drop: Cell::new(true), - } - } - - /// Prevents this guard from dropping the supplied pointer. - /// - /// # Safety - /// - /// This function is unsafe in order to prevent safe code from forgetting this guard. It should - /// only be called by the macros in this module. - #[inline] - pub unsafe fn forget(&self) { - self.do_drop.set(false); + Self { ptr } } } impl<T: ?Sized> Drop for DropGuard<T> { #[inline] fn drop(&mut self) { - if self.do_drop.get() { - // SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function - // ensuring that this operation is safe. - unsafe { ptr::drop_in_place(self.ptr) } - } + // SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function + // ensuring that this operation is safe. + unsafe { ptr::drop_in_place(self.ptr) } } } diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 00aa4e956c0a..cb6e61b6c50b 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1,10 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT //! This module provides the macros that actually implement the proc-macros `pin_data` and -//! `pinned_drop`. +//! `pinned_drop`. It also contains `__init_internal` the implementation of the `{try_}{pin_}init!` +//! macros. //! //! These macros should never be called directly, since they expect their input to be -//! in a certain format which is internal. Use the proc-macros instead. +//! in a certain format which is internal. If used incorrectly, these macros can lead to UB even in +//! safe code! Use the public facing macros instead. //! //! This architecture has been chosen because the kernel does not yet have access to `syn` which //! would make matters a lot easier for implementing these as proc-macros. @@ -43,7 +45,7 @@ //! #[pinned_drop] //! impl PinnedDrop for Foo { //! fn drop(self: Pin<&mut Self>) { -//! println!("{self:p} is getting dropped."); +//! pr_info!("{self:p} is getting dropped."); //! } //! } //! @@ -168,8 +170,10 @@ //! t: T, //! } //! #[doc(hidden)] -//! impl<'__pin, T> -//! ::core::marker::Unpin for Bar<T> where __Unpin<'__pin, T>: ::core::marker::Unpin {} +//! impl<'__pin, T> ::core::marker::Unpin for Bar<T> +//! where +//! __Unpin<'__pin, T>: ::core::marker::Unpin, +//! {} //! // Now we need to ensure that `Bar` does not implement `Drop`, since that would give users //! // access to `&mut self` inside of `drop` even if the struct was pinned. This could lead to //! // UB with only safe code, so we disallow this by giving a trait implementation error using @@ -186,8 +190,9 @@ //! // for safety, but a good sanity check, since no normal code calls `PinnedDrop::drop`. //! #[allow(non_camel_case_types)] //! trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} -//! impl<T: ::kernel::init::PinnedDrop> -//! UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} +//! impl< +//! T: ::kernel::init::PinnedDrop, +//! > UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} //! impl<T> UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for Bar<T> {} //! }; //! ``` @@ -217,7 +222,7 @@ //! // return type and shadow it later when we insert the arbitrary user code. That way //! // there will be no possibility of returning without `unsafe`. //! struct __InitOk; -//! // Get the pin-data type from the initialized type. +//! // Get the data about fields from the supplied type. //! // - the function is unsafe, hence the unsafe block //! // - we `use` the `HasPinData` trait in the block, it is only available in that //! // scope. @@ -225,8 +230,7 @@ //! use ::kernel::init::__internal::HasPinData; //! Self::__pin_data() //! }; -//! // Use `data` to help with type inference, the closure supplied will have the type -//! // `FnOnce(*mut Self) -> Result<__InitOk, Infallible>`. +//! // Ensure that `data` really is of type `PinData` and help with type inference: //! let init = ::kernel::init::__internal::PinData::make_closure::< //! _, //! __InitOk, @@ -234,71 +238,75 @@ //! >(data, move |slot| { //! { //! // Shadow the structure so it cannot be used to return early. If a user -//! // tries to write `return Ok(__InitOk)`, then they get a type error, since -//! // that will refer to this struct instead of the one defined above. +//! // tries to write `return Ok(__InitOk)`, then they get a type error, +//! // since that will refer to this struct instead of the one defined +//! // above. //! struct __InitOk; //! // This is the expansion of `t,`, which is syntactic sugar for `t: t,`. -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).t), t) }; -//! // Since initialization could fail later (not in this case, since the error -//! // type is `Infallible`) we will need to drop this field if there is an -//! // error later. This `DropGuard` will drop the field when it gets dropped -//! // and has not yet been forgotten. We make a reference to it, so users -//! // cannot `mem::forget` it from the initializer, since the name is the same -//! // as the field (including hygiene). -//! let t = &unsafe { -//! ::kernel::init::__internal::DropGuard::new( -//! ::core::addr_of_mut!((*slot).t), -//! ) +//! { +//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).t), t) }; +//! } +//! // Since initialization could fail later (not in this case, since the +//! // error type is `Infallible`) we will need to drop this field if there +//! // is an error later. This `DropGuard` will drop the field when it gets +//! // dropped and has not yet been forgotten. +//! let t = unsafe { +//! ::pinned_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).t)) //! }; //! // Expansion of `x: 0,`: -//! // Since this can be an arbitrary expression we cannot place it inside of -//! // the `unsafe` block, so we bind it here. -//! let x = 0; -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).x), x) }; +//! // Since this can be an arbitrary expression we cannot place it inside +//! // of the `unsafe` block, so we bind it here. +//! { +//! let x = 0; +//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).x), x) }; +//! } //! // We again create a `DropGuard`. -//! let x = &unsafe { -//! ::kernel::init::__internal::DropGuard::new( -//! ::core::addr_of_mut!((*slot).x), -//! ) +//! let x = unsafe { +//! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).x)) //! }; -//! +//! // Since initialization has successfully completed, we can now forget +//! // the guards. This is not `mem::forget`, since we only have +//! // `&DropGuard`. +//! ::core::mem::forget(x); +//! ::core::mem::forget(t); //! // Here we use the type checker to ensure that every field has been //! // initialized exactly once, since this is `if false` it will never get //! // executed, but still type-checked. -//! // Additionally we abuse `slot` to automatically infer the correct type for -//! // the struct. This is also another check that every field is accessible -//! // from this scope. +//! // Additionally we abuse `slot` to automatically infer the correct type +//! // for the struct. This is also another check that every field is +//! // accessible from this scope. //! #[allow(unreachable_code, clippy::diverging_sub_expression)] -//! if false { +//! let _ = || { //! unsafe { //! ::core::ptr::write( //! slot, //! Self { -//! // We only care about typecheck finding every field here, -//! // the expression does not matter, just conjure one using -//! // `panic!()`: +//! // We only care about typecheck finding every field +//! // here, the expression does not matter, just conjure +//! // one using `panic!()`: //! t: ::core::panic!(), //! x: ::core::panic!(), //! }, //! ); //! }; -//! } -//! // Since initialization has successfully completed, we can now forget the -//! // guards. This is not `mem::forget`, since we only have `&DropGuard`. -//! unsafe { ::kernel::init::__internal::DropGuard::forget(t) }; -//! unsafe { ::kernel::init::__internal::DropGuard::forget(x) }; +//! }; //! } //! // We leave the scope above and gain access to the previously shadowed //! // `__InitOk` that we need to return. //! Ok(__InitOk) //! }); //! // Change the return type from `__InitOk` to `()`. -//! let init = move |slot| -> ::core::result::Result<(), ::core::convert::Infallible> { +//! let init = move | +//! slot, +//! | -> ::core::result::Result<(), ::core::convert::Infallible> { //! init(slot).map(|__InitOk| ()) //! }; //! // Construct the initializer. //! let init = unsafe { -//! ::kernel::init::pin_init_from_closure::<_, ::core::convert::Infallible>(init) +//! ::kernel::init::pin_init_from_closure::< +//! _, +//! ::core::convert::Infallible, +//! >(init) //! }; //! init //! } @@ -372,7 +380,10 @@ //! b: Bar<u32>, //! } //! #[doc(hidden)] -//! impl<'__pin> ::core::marker::Unpin for Foo where __Unpin<'__pin>: ::core::marker::Unpin {} +//! impl<'__pin> ::core::marker::Unpin for Foo +//! where +//! __Unpin<'__pin>: ::core::marker::Unpin, +//! {} //! // Since we specified `PinnedDrop` as the argument to `#[pin_data]`, we expect `Foo` to //! // implement `PinnedDrop`. Thus we do not need to prevent `Drop` implementations like //! // before, instead we implement `Drop` here and delegate to `PinnedDrop`. @@ -401,7 +412,7 @@ //! #[pinned_drop] //! impl PinnedDrop for Foo { //! fn drop(self: Pin<&mut Self>) { -//! println!("{self:p} is getting dropped."); +//! pr_info!("{self:p} is getting dropped."); //! } //! } //! ``` @@ -412,7 +423,7 @@ //! // `unsafe`, full path and the token parameter are added, everything else stays the same. //! unsafe impl ::kernel::init::PinnedDrop for Foo { //! fn drop(self: Pin<&mut Self>, _: ::kernel::init::__internal::OnlyCallFromDrop) { -//! println!("{self:p} is getting dropped."); +//! pr_info!("{self:p} is getting dropped."); //! } //! } //! ``` @@ -447,18 +458,21 @@ //! >(data, move |slot| { //! { //! struct __InitOk; -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).a), a) }; -//! let a = &unsafe { +//! { +//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).a), a) }; +//! } +//! let a = unsafe { //! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).a)) //! }; -//! let b = Bar::new(36); +//! let init = Bar::new(36); //! unsafe { data.b(::core::addr_of_mut!((*slot).b), b)? }; -//! let b = &unsafe { +//! let b = unsafe { //! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).b)) //! }; -//! +//! ::core::mem::forget(b); +//! ::core::mem::forget(a); //! #[allow(unreachable_code, clippy::diverging_sub_expression)] -//! if false { +//! let _ = || { //! unsafe { //! ::core::ptr::write( //! slot, @@ -468,13 +482,13 @@ //! }, //! ); //! }; -//! } -//! unsafe { ::kernel::init::__internal::DropGuard::forget(a) }; -//! unsafe { ::kernel::init::__internal::DropGuard::forget(b) }; +//! }; //! } //! Ok(__InitOk) //! }); -//! let init = move |slot| -> ::core::result::Result<(), ::core::convert::Infallible> { +//! let init = move | +//! slot, +//! | -> ::core::result::Result<(), ::core::convert::Infallible> { //! init(slot).map(|__InitOk| ()) //! }; //! let init = unsafe { @@ -960,6 +974,7 @@ macro_rules! __pin_data { where $($whr)* { $( + $(#[$($p_attr)*])* $pvis unsafe fn $p_field<E>( self, slot: *mut $p_type, @@ -969,6 +984,7 @@ macro_rules! __pin_data { } )* $( + $(#[$($attr)*])* $fvis unsafe fn $field<E>( self, slot: *mut $type, @@ -980,3 +996,388 @@ macro_rules! __pin_data { } }; } + +/// The internal init macro. Do not call manually! +/// +/// This is called by the `{try_}{pin_}init!` macros with various inputs. +/// +/// This macro has multiple internal call configurations, these are always the very first ident: +/// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros. +/// - `with_update_parsed`: when the `..Zeroable::zeroed()` syntax has been handled. +/// - `init_slot`: recursively creates the code that initializes all fields in `slot`. +/// - `make_initializer`: recursively create the struct initializer that guarantees that every +/// field has been initialized exactly once. +#[doc(hidden)] +#[macro_export] +macro_rules! __init_internal { + ( + @this($($this:ident)?), + @typ($t:path), + @fields($($fields:tt)*), + @error($err:ty), + // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` + // case. + @data($data:ident, $($use_data:ident)?), + // `HasPinData` or `HasInitData`. + @has_data($has_data:ident, $get_data:ident), + // `pin_init_from_closure` or `init_from_closure`. + @construct_closure($construct_closure:ident), + @munch_fields(), + ) => { + $crate::__init_internal!(with_update_parsed: + @this($($this)?), + @typ($t), + @fields($($fields)*), + @error($err), + @data($data, $($use_data)?), + @has_data($has_data, $get_data), + @construct_closure($construct_closure), + @zeroed(), // Nothing means default behavior. + ) + }; + ( + @this($($this:ident)?), + @typ($t:path), + @fields($($fields:tt)*), + @error($err:ty), + // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` + // case. + @data($data:ident, $($use_data:ident)?), + // `HasPinData` or `HasInitData`. + @has_data($has_data:ident, $get_data:ident), + // `pin_init_from_closure` or `init_from_closure`. + @construct_closure($construct_closure:ident), + @munch_fields(..Zeroable::zeroed()), + ) => { + $crate::__init_internal!(with_update_parsed: + @this($($this)?), + @typ($t), + @fields($($fields)*), + @error($err), + @data($data, $($use_data)?), + @has_data($has_data, $get_data), + @construct_closure($construct_closure), + @zeroed(()), // `()` means zero all fields not mentioned. + ) + }; + ( + @this($($this:ident)?), + @typ($t:path), + @fields($($fields:tt)*), + @error($err:ty), + // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` + // case. + @data($data:ident, $($use_data:ident)?), + // `HasPinData` or `HasInitData`. + @has_data($has_data:ident, $get_data:ident), + // `pin_init_from_closure` or `init_from_closure`. + @construct_closure($construct_closure:ident), + @munch_fields($ignore:tt $($rest:tt)*), + ) => { + $crate::__init_internal!( + @this($($this)?), + @typ($t), + @fields($($fields)*), + @error($err), + @data($data, $($use_data)?), + @has_data($has_data, $get_data), + @construct_closure($construct_closure), + @munch_fields($($rest)*), + ) + }; + (with_update_parsed: + @this($($this:ident)?), + @typ($t:path), + @fields($($fields:tt)*), + @error($err:ty), + // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` + // case. + @data($data:ident, $($use_data:ident)?), + // `HasPinData` or `HasInitData`. + @has_data($has_data:ident, $get_data:ident), + // `pin_init_from_closure` or `init_from_closure`. + @construct_closure($construct_closure:ident), + @zeroed($($init_zeroed:expr)?), + ) => {{ + // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return + // type and shadow it later when we insert the arbitrary user code. That way there will be + // no possibility of returning without `unsafe`. + struct __InitOk; + // Get the data about fields from the supplied type. + let data = unsafe { + use $crate::init::__internal::$has_data; + // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal + // information that is associated to already parsed fragments, so a path fragment + // cannot be used in this position. Doing the retokenization results in valid rust + // code. + ::kernel::macros::paste!($t::$get_data()) + }; + // Ensure that `data` really is of type `$data` and help with type inference: + let init = $crate::init::__internal::$data::make_closure::<_, __InitOk, $err>( + data, + move |slot| { + { + // Shadow the structure so it cannot be used to return early. + struct __InitOk; + // If `$init_zeroed` is present we should zero the slot now and not emit an + // error when fields are missing (since they will be zeroed). We also have to + // check that the type actually implements `Zeroable`. + $({ + fn assert_zeroable<T: $crate::init::Zeroable>(_: *mut T) {} + // Ensure that the struct is indeed `Zeroable`. + assert_zeroable(slot); + // SAFETY: The type implements `Zeroable` by the check above. + unsafe { ::core::ptr::write_bytes(slot, 0, 1) }; + $init_zeroed // This will be `()` if set. + })? + // Create the `this` so it can be referenced by the user inside of the + // expressions creating the individual fields. + $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? + // Initialize every field. + $crate::__init_internal!(init_slot($($use_data)?): + @data(data), + @slot(slot), + @guards(), + @munch_fields($($fields)*,), + ); + // We use unreachable code to ensure that all fields have been mentioned exactly + // once, this struct initializer will still be type-checked and complain with a + // very natural error message if a field is forgotten/mentioned more than once. + #[allow(unreachable_code, clippy::diverging_sub_expression)] + let _ = || { + $crate::__init_internal!(make_initializer: + @slot(slot), + @type_name($t), + @munch_fields($($fields)*,), + @acc(), + ); + }; + } + Ok(__InitOk) + } + ); + let init = move |slot| -> ::core::result::Result<(), $err> { + init(slot).map(|__InitOk| ()) + }; + let init = unsafe { $crate::init::$construct_closure::<_, $err>(init) }; + init + }}; + (init_slot($($use_data:ident)?): + @data($data:ident), + @slot($slot:ident), + @guards($($guards:ident,)*), + @munch_fields($(..Zeroable::zeroed())? $(,)?), + ) => { + // Endpoint of munching, no fields are left. If execution reaches this point, all fields + // have been initialized. Therefore we can now dismiss the guards by forgetting them. + $(::core::mem::forget($guards);)* + }; + (init_slot($use_data:ident): // `use_data` is present, so we use the `data` to init fields. + @data($data:ident), + @slot($slot:ident), + @guards($($guards:ident,)*), + // In-place initialization syntax. + @munch_fields($field:ident <- $val:expr, $($rest:tt)*), + ) => { + let init = $val; + // Call the initializer. + // + // SAFETY: `slot` is valid, because we are inside of an initializer closure, we + // return when an error/panic occurs. + // We also use the `data` to require the correct trait (`Init` or `PinInit`) for `$field`. + unsafe { $data.$field(::core::ptr::addr_of_mut!((*$slot).$field), init)? }; + // Create the drop guard: + // + // We rely on macro hygiene to make it impossible for users to access this local variable. + // We use `paste!` to create new hygiene for `$field`. + ::kernel::macros::paste! { + // SAFETY: We forget the guard later when initialization has succeeded. + let [<$field>] = unsafe { + $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) + }; + + $crate::__init_internal!(init_slot($use_data): + @data($data), + @slot($slot), + @guards([<$field>], $($guards,)*), + @munch_fields($($rest)*), + ); + } + }; + (init_slot(): // No `use_data`, so we use `Init::__init` directly. + @data($data:ident), + @slot($slot:ident), + @guards($($guards:ident,)*), + // In-place initialization syntax. + @munch_fields($field:ident <- $val:expr, $($rest:tt)*), + ) => { + let init = $val; + // Call the initializer. + // + // SAFETY: `slot` is valid, because we are inside of an initializer closure, we + // return when an error/panic occurs. + unsafe { $crate::init::Init::__init(init, ::core::ptr::addr_of_mut!((*$slot).$field))? }; + // Create the drop guard: + // + // We rely on macro hygiene to make it impossible for users to access this local variable. + // We use `paste!` to create new hygiene for `$field`. + ::kernel::macros::paste! { + // SAFETY: We forget the guard later when initialization has succeeded. + let [<$field>] = unsafe { + $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) + }; + + $crate::__init_internal!(init_slot(): + @data($data), + @slot($slot), + @guards([<$field>], $($guards,)*), + @munch_fields($($rest)*), + ); + } + }; + (init_slot($($use_data:ident)?): + @data($data:ident), + @slot($slot:ident), + @guards($($guards:ident,)*), + // Init by-value. + @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), + ) => { + { + $(let $field = $val;)? + // Initialize the field. + // + // SAFETY: The memory at `slot` is uninitialized. + unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) }; + } + // Create the drop guard: + // + // We rely on macro hygiene to make it impossible for users to access this local variable. + // We use `paste!` to create new hygiene for `$field`. + ::kernel::macros::paste! { + // SAFETY: We forget the guard later when initialization has succeeded. + let [<$field>] = unsafe { + $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) + }; + + $crate::__init_internal!(init_slot($($use_data)?): + @data($data), + @slot($slot), + @guards([<$field>], $($guards,)*), + @munch_fields($($rest)*), + ); + } + }; + (make_initializer: + @slot($slot:ident), + @type_name($t:path), + @munch_fields(..Zeroable::zeroed() $(,)?), + @acc($($acc:tt)*), + ) => { + // Endpoint, nothing more to munch, create the initializer. Since the users specified + // `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have + // not been overwritten are thus zero and initialized. We still check that all fields are + // actually accessible by using the struct update syntax ourselves. + // We are inside of a closure that is never executed and thus we can abuse `slot` to + // get the correct type inference here: + #[allow(unused_assignments)] + unsafe { + let mut zeroed = ::core::mem::zeroed(); + // We have to use type inference here to make zeroed have the correct type. This does + // not get executed, so it has no effect. + ::core::ptr::write($slot, zeroed); + zeroed = ::core::mem::zeroed(); + // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal + // information that is associated to already parsed fragments, so a path fragment + // cannot be used in this position. Doing the retokenization results in valid rust + // code. + ::kernel::macros::paste!( + ::core::ptr::write($slot, $t { + $($acc)* + ..zeroed + }); + ); + } + }; + (make_initializer: + @slot($slot:ident), + @type_name($t:path), + @munch_fields($(,)?), + @acc($($acc:tt)*), + ) => { + // Endpoint, nothing more to munch, create the initializer. + // Since we are in the closure that is never called, this will never get executed. + // We abuse `slot` to get the correct type inference here: + unsafe { + // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal + // information that is associated to already parsed fragments, so a path fragment + // cannot be used in this position. Doing the retokenization results in valid rust + // code. + ::kernel::macros::paste!( + ::core::ptr::write($slot, $t { + $($acc)* + }); + ); + } + }; + (make_initializer: + @slot($slot:ident), + @type_name($t:path), + @munch_fields($field:ident <- $val:expr, $($rest:tt)*), + @acc($($acc:tt)*), + ) => { + $crate::__init_internal!(make_initializer: + @slot($slot), + @type_name($t), + @munch_fields($($rest)*), + @acc($($acc)* $field: ::core::panic!(),), + ); + }; + (make_initializer: + @slot($slot:ident), + @type_name($t:path), + @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), + @acc($($acc:tt)*), + ) => { + $crate::__init_internal!(make_initializer: + @slot($slot), + @type_name($t), + @munch_fields($($rest)*), + @acc($($acc)* $field: ::core::panic!(),), + ); + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __derive_zeroable { + (parse_input: + @sig( + $(#[$($struct_attr:tt)*])* + $vis:vis struct $name:ident + $(where $($whr:tt)*)? + ), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @body({ + $( + $(#[$($field_attr:tt)*])* + $field:ident : $field_ty:ty + ),* $(,)? + }), + ) => { + // SAFETY: Every field type implements `Zeroable` and padding bytes may be zero. + #[automatically_derived] + unsafe impl<$($impl_generics)*> $crate::init::Zeroable for $name<$($ty_generics)*> + where + $($($whr)*)? + {} + const _: () = { + fn assert_zeroable<T: ?::core::marker::Sized + $crate::init::Zeroable>() {} + fn ensure_zeroable<$($impl_generics)*>() + where $($($whr)*)? + { + $(assert_zeroable::<$field_ty>();)* + } + }; + }; +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3642cadc34b1..e8811700239a 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -95,7 +95,4 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! { pr_emerg!("{}\n", info); // SAFETY: FFI call. unsafe { bindings::BUG() }; - // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()` - // instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>. - loop {} } diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index c28587d68ebc..ae21600970b3 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -18,7 +18,7 @@ pub use core::pin::Pin; pub use alloc::{boxed::Box, vec::Vec}; #[doc(no_inline)] -pub use macros::{module, pin_data, pinned_drop, vtable}; +pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable}; pub use super::build_assert; diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index a2216325632d..70a785f04754 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -72,8 +72,8 @@ pub unsafe trait Backend { /// A mutual exclusion primitive. /// -/// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock backend -/// specified as the generic parameter `B`. +/// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock +/// [`Backend`] specified as the generic parameter `B`. #[pin_data] pub struct Lock<T: ?Sized, B: Backend> { /// The kernel lock object. @@ -126,7 +126,7 @@ impl<T: ?Sized, B: Backend> Lock<T, B> { /// A lock guard. /// -/// Allows mutual exclusion primitives that implement the `Backend` trait to automatically unlock +/// Allows mutual exclusion primitives that implement the [`Backend`] trait to automatically unlock /// when a guard goes out of scope. It also provides a safe and convenient way to access the data /// protected by the lock. #[must_use = "the lock unlocks immediately when the guard is unused"] diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index e33b901ab0a4..fdb778e65d79 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -6,7 +6,7 @@ use crate::init::{self, PinInit}; use alloc::boxed::Box; use core::{ cell::UnsafeCell, - marker::PhantomData, + marker::{PhantomData, PhantomPinned}, mem::MaybeUninit, ops::{Deref, DerefMut}, ptr::NonNull, @@ -206,17 +206,26 @@ impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> { /// /// This is meant to be used with FFI objects that are never interpreted by Rust code. #[repr(transparent)] -pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>); +pub struct Opaque<T> { + value: UnsafeCell<MaybeUninit<T>>, + _pin: PhantomPinned, +} impl<T> Opaque<T> { /// Creates a new opaque value. pub const fn new(value: T) -> Self { - Self(MaybeUninit::new(UnsafeCell::new(value))) + Self { + value: UnsafeCell::new(MaybeUninit::new(value)), + _pin: PhantomPinned, + } } /// Creates an uninitialised value. pub const fn uninit() -> Self { - Self(MaybeUninit::uninit()) + Self { + value: UnsafeCell::new(MaybeUninit::uninit()), + _pin: PhantomPinned, + } } /// Creates a pin-initializer from the given initializer closure. @@ -240,7 +249,7 @@ impl<T> Opaque<T> { /// Returns a raw pointer to the opaque data. pub fn get(&self) -> *mut T { - UnsafeCell::raw_get(self.0.as_ptr()) + UnsafeCell::get(&self.value).cast::<T>() } /// Gets the value behind `this`. @@ -248,7 +257,7 @@ impl<T> Opaque<T> { /// This function is useful to get access to the value without creating intermediate /// references. pub const fn raw_get(this: *const Self) -> *mut T { - UnsafeCell::raw_get(this.cast::<UnsafeCell<T>>()) + UnsafeCell::raw_get(this.cast::<UnsafeCell<MaybeUninit<T>>>()).cast::<T>() } } |