mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 23:13:01 +02:00
rust: add extensions to the pin-init crate and move relevant documentation there
In preparation of splitting off the pin-init crate from the kernel
crate, move all kernel-specific documentation from pin-init back into
the kernel crate.
Also include an example from the user-space version [1] adapted to the
kernel.
The new `init.rs` file will also be populated by kernel-specific
extensions to the pin-init crate by the next commits.
Link: c1417c64c7/src/lib.rs (L161)
[1]
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Fiona Behrens <me@kloenk.dev>
Tested-by: Andreas Hindborg <a.hindborg@kernel.org>
Link: https://lore.kernel.org/r/20250308110339.2997091-4-benno.lossin@proton.me
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
fbf8fb328d
commit
86f7dacade
135
rust/kernel/init.rs
Normal file
135
rust/kernel/init.rs
Normal file
|
@ -0,0 +1,135 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//! Extensions to the [`pin-init`] crate.
|
||||
//!
|
||||
//! Most `struct`s from the [`sync`] module need to be pinned, because they contain self-referential
|
||||
//! `struct`s from C. [Pinning][pinning] is Rust's way of ensuring data does not move.
|
||||
//!
|
||||
//! The [`pin-init`] crate is the way such structs are initialized on the Rust side. Please refer
|
||||
//! to its documentation to better understand how to use it. Additionally, there are many examples
|
||||
//! throughout the kernel, such as the types from the [`sync`] module. And the ones presented
|
||||
//! below.
|
||||
//!
|
||||
//! [`sync`]: crate::sync
|
||||
//! [pinning]: https://doc.rust-lang.org/std/pin/index.html
|
||||
//! [`pin-init`]: https://rust.docs.kernel.org/pin_init/
|
||||
//!
|
||||
//! # [`Opaque<T>`]
|
||||
//!
|
||||
//! For the special case where initializing a field is a single FFI-function call that cannot fail,
|
||||
//! there exist the helper function [`Opaque::ffi_init`]. This function initialize a single
|
||||
//! [`Opaque<T>`] field by just delegating to the supplied closure. You can use these in
|
||||
//! combination with [`pin_init!`].
|
||||
//!
|
||||
//! [`Opaque<T>`]: crate::types::Opaque
|
||||
//! [`Opaque::ffi_init`]: crate::types::Opaque::ffi_init
|
||||
//! [`pin_init!`]: crate::pin_init
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ## General Examples
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! # #![allow(clippy::disallowed_names)]
|
||||
//! use kernel::types::Opaque;
|
||||
//! use pin_init::pin_init_from_closure;
|
||||
//!
|
||||
//! // assume we have some `raw_foo` type in C:
|
||||
//! #[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| {
|
||||
//! // note that this cannot fail.
|
||||
//! init_foo(s);
|
||||
//! })
|
||||
//! },
|
||||
//! }).pin_chain(|foo| {
|
||||
//! foo.setup();
|
||||
//! Ok(())
|
||||
//! });
|
||||
//! ```
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! # #![allow(unreachable_pub, clippy::disallowed_names)]
|
||||
//! use kernel::{prelude::*, types::Opaque};
|
||||
//! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin};
|
||||
//! # mod bindings {
|
||||
//! # #![allow(non_camel_case_types)]
|
||||
//! # pub struct foo;
|
||||
//! # pub unsafe fn init_foo(_ptr: *mut foo) {}
|
||||
//! # pub unsafe fn destroy_foo(_ptr: *mut foo) {}
|
||||
//! # pub unsafe fn enable_foo(_ptr: *mut foo, _flags: u32) -> i32 { 0 }
|
||||
//! # }
|
||||
//! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround.
|
||||
//! # trait FromErrno {
|
||||
//! # fn from_errno(errno: core::ffi::c_int) -> Error {
|
||||
//! # // Dummy error that can be constructed outside the `kernel` crate.
|
||||
//! # Error::from(core::fmt::Error)
|
||||
//! # }
|
||||
//! # }
|
||||
//! # impl FromErrno for Error {}
|
||||
//! /// # Invariants
|
||||
//! ///
|
||||
//! /// `foo` is always initialized
|
||||
//! #[pin_data(PinnedDrop)]
|
||||
//! pub struct RawFoo {
|
||||
//! #[pin]
|
||||
//! foo: Opaque<bindings::foo>,
|
||||
//! #[pin]
|
||||
//! _p: PhantomPinned,
|
||||
//! }
|
||||
//!
|
||||
//! impl RawFoo {
|
||||
//! pub fn new(flags: u32) -> impl PinInit<Self, Error> {
|
||||
//! // SAFETY:
|
||||
//! // - when the closure returns `Ok(())`, then it has successfully initialized and
|
||||
//! // enabled `foo`,
|
||||
//! // - when it returns `Err(e)`, then it has cleaned up before
|
||||
//! unsafe {
|
||||
//! pin_init::pin_init_from_closure(move |slot: *mut Self| {
|
||||
//! // `slot` contains uninit memory, avoid creating a reference.
|
||||
//! let foo = addr_of_mut!((*slot).foo);
|
||||
//!
|
||||
//! // Initialize the `foo`
|
||||
//! bindings::init_foo(Opaque::raw_get(foo));
|
||||
//!
|
||||
//! // Try to enable it.
|
||||
//! let err = bindings::enable_foo(Opaque::raw_get(foo), flags);
|
||||
//! if err != 0 {
|
||||
//! // Enabling has failed, first clean up the foo and then return the error.
|
||||
//! bindings::destroy_foo(Opaque::raw_get(foo));
|
||||
//! return Err(Error::from_errno(err));
|
||||
//! }
|
||||
//!
|
||||
//! // All fields of `RawFoo` have been initialized, since `_p` is a ZST.
|
||||
//! Ok(())
|
||||
//! })
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[pinned_drop]
|
||||
//! impl PinnedDrop for RawFoo {
|
||||
//! fn drop(self: Pin<&mut Self>) {
|
||||
//! // SAFETY: Since `foo` is initialized, destroying is safe.
|
||||
//! unsafe { bindings::destroy_foo(self.foo.get()) };
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
|
@ -52,6 +52,9 @@ pub mod firmware;
|
|||
pub mod fs;
|
||||
#[path = "../pin-init/src/lib.rs"]
|
||||
pub mod init;
|
||||
// momentarily use the name `init_ext` and set the path manually
|
||||
#[path = "init.rs"]
|
||||
pub mod init_ext;
|
||||
pub mod io;
|
||||
pub mod ioctl;
|
||||
pub mod jump_label;
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
//! It also allows in-place initialization of big `struct`s that would otherwise produce a stack
|
||||
//! overflow.
|
||||
//!
|
||||
//! Most `struct`s from the [`sync`] module need to be pinned, because they contain self-referential
|
||||
//! `struct`s from C. [Pinning][pinning] is Rust's way of ensuring data does not move.
|
||||
//!
|
||||
//! # Overview
|
||||
//!
|
||||
//! To initialize a `struct` with an in-place constructor you will need two things:
|
||||
|
@ -188,15 +185,6 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! For the special case where initializing a field is a single FFI-function call that cannot fail,
|
||||
//! there exist the helper function [`Opaque::ffi_init`]. This function initialize a single
|
||||
//! [`Opaque`] field by just delegating to the supplied closure. You can use these in combination
|
||||
//! with [`pin_init!`].
|
||||
//!
|
||||
//! For more information on how to use [`pin_init_from_closure()`], take a look at the uses inside
|
||||
//! the `kernel` crate. The [`sync`] module is a good starting point.
|
||||
//!
|
||||
//! [`sync`]: kernel::sync
|
||||
//! [pinning]: https://doc.rust-lang.org/std/pin/index.html
|
||||
//! [structurally pinned fields]:
|
||||
//! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
|
||||
|
@ -205,8 +193,6 @@
|
|||
//! [`impl PinInit<Foo>`]: PinInit
|
||||
//! [`impl PinInit<T, E>`]: PinInit
|
||||
//! [`impl Init<T, E>`]: Init
|
||||
//! [`Opaque`]: kernel::types::Opaque
|
||||
//! [`Opaque::ffi_init`]: kernel::types::Opaque::ffi_init
|
||||
//! [`pin_data`]: ::macros::pin_data
|
||||
//! [`pin_init!`]: crate::pin_init!
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user