From: Danilo Krummrich <dakr@redhat.com>
To: Benno Lossin <benno.lossin@proton.me>, gregkh@linuxfoundation.org
Cc: rafael@kernel.org, mcgrof@kernel.org, russ.weight@linux.dev,
ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com,
boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com,
a.hindborg@samsung.com, aliceryhl@google.com, airlied@gmail.com,
fujita.tomonori@gmail.com, pstanner@redhat.com,
ajanulgu@redhat.com, lyude@redhat.com,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v4 2/2] rust: add firmware abstractions
Date: Wed, 19 Jun 2024 11:44:23 +0200 [thread overview]
Message-ID: <ZnKod6Wn5louhPu8@pollux> (raw)
In-Reply-To: <8d6f98c2-afe2-4e94-b630-96a8fa0b39cf@proton.me>
Greg,
Benno's comments provide some nice hints to further improve the safety comments.
Since I was notified that those patches hit your tree already, how do you want
to proceed?
- Danilo
On Wed, Jun 19, 2024 at 08:58:02AM +0000, Benno Lossin wrote:
> On 18.06.24 17:48, Danilo Krummrich wrote:
> > Add an abstraction around the kernels firmware API to request firmware
> > images. The abstraction provides functions to access the firmware's size
> > and backing buffer.
> >
> > The firmware is released once the abstraction instance is dropped.
> >
> > Signed-off-by: Danilo Krummrich <dakr@redhat.com>
> > ---
> > drivers/base/firmware_loader/Kconfig | 7 ++
> > rust/bindings/bindings_helper.h | 1 +
> > rust/kernel/firmware.rs | 101 +++++++++++++++++++++++++++
> > rust/kernel/lib.rs | 2 +
> > 4 files changed, 111 insertions(+)
> > create mode 100644 rust/kernel/firmware.rs
> >
> > diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig
> > index 5ca00e02fe82..a03701674265 100644
> > --- a/drivers/base/firmware_loader/Kconfig
> > +++ b/drivers/base/firmware_loader/Kconfig
> > @@ -37,6 +37,13 @@ config FW_LOADER_DEBUG
> > SHA256 checksums to the kernel log for each firmware file that is
> > loaded.
> >
> > +config RUST_FW_LOADER_ABSTRACTIONS
> > + bool "Rust Firmware Loader abstractions"
> > + depends on RUST
> > + depends on FW_LOADER=y
> > + help
> > + This enables the Rust abstractions for the firmware loader API.
> > +
> > if FW_LOADER
> >
> > config FW_LOADER_PAGED_BUF
> > diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> > index ddb5644d4fd9..18a3f05115cb 100644
> > --- a/rust/bindings/bindings_helper.h
> > +++ b/rust/bindings/bindings_helper.h
> > @@ -9,6 +9,7 @@
> > #include <kunit/test.h>
> > #include <linux/errname.h>
> > #include <linux/ethtool.h>
> > +#include <linux/firmware.h>
> > #include <linux/jiffies.h>
> > #include <linux/mdio.h>
> > #include <linux/phy.h>
> > diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs
> > new file mode 100644
> > index 000000000000..b55ea1b45368
> > --- /dev/null
> > +++ b/rust/kernel/firmware.rs
> > @@ -0,0 +1,101 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +//! Firmware abstraction
> > +//!
> > +//! C header: [`include/linux/firmware.h`](srctree/include/linux/firmware.h")
> > +
> > +use crate::{bindings, device::Device, error::Error, error::Result, str::CStr};
> > +use core::ptr::NonNull;
> > +
> > +// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
> > +// `firmware_request_platform`, `bindings::request_firmware_direct`
> > +type FwFunc =
> > + unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut bindings::device) -> i32;
> > +
> > +/// Abstraction around a C `struct firmware`.
> > +///
> > +/// This is a simple abstraction around the C firmware API. Just like with the C API, firmware can
> > +/// be requested. Once requested the abstraction provides direct access to the firmware buffer as
> > +/// `&[u8]`. The firmware is released once [`Firmware`] is dropped.
> > +///
> > +/// # Invariants
> > +///
> > +/// The pointer is valid, and has ownership over the instance of `struct firmware`.
> > +///
> > +/// Once requested, the `Firmware` backing buffer is not modified until it is freed when `Firmware`
> > +/// is dropped.
>
> This can simply be "The `firmware`'s backing buffer is not modified."
> Since I interpret "Once requested" as "Once created" and you are allowed
> to break invariants as long as nobody can observe that.
>
> > +///
> > +/// # Examples
> > +///
> > +/// ```
> > +/// # use kernel::{c_str, device::Device, firmware::Firmware};
> > +///
> > +/// # // SAFETY: *NOT* safe, just for the example to get an `ARef<Device>` instance
> > +/// # let dev = unsafe { Device::from_raw(core::ptr::null_mut()) };
> > +///
> > +/// let fw = Firmware::request(c_str!("path/to/firmware.bin"), &dev).unwrap();
> > +/// let blob = fw.data();
> > +/// ```
> > +pub struct Firmware(NonNull<bindings::firmware>);
> > +
> > +impl Firmware {
> > + fn request_internal(name: &CStr, dev: &Device, func: FwFunc) -> Result<Self> {
> > + let mut fw: *mut bindings::firmware = core::ptr::null_mut();
> > + let pfw: *mut *mut bindings::firmware = &mut fw;
> > +
> > + // SAFETY: `pfw` is a valid pointer to a NULL initialized `bindings::firmware` pointer.
> > + // `name` and `dev` are valid as by their type invariants.
> > + let ret = unsafe { func(pfw as _, name.as_char_ptr(), dev.as_raw()) };
> > + if ret != 0 {
> > + return Err(Error::from_errno(ret));
> > + }
> > +
> > + // SAFETY: `func` not bailing out with a non-zero error code, guarantees that `fw` is a
> > + // valid pointer to `bindings::firmware`.
> > + Ok(Firmware(unsafe { NonNull::new_unchecked(fw) }))
> > + }
> > +
> > + /// Send a firmware request and wait for it. See also `bindings::request_firmware`.
> > + pub fn request(name: &CStr, dev: &Device) -> Result<Self> {
> > + Self::request_internal(name, dev, bindings::request_firmware)
> > + }
> > +
> > + /// Send a request for an optional firmware module. See also
> > + /// `bindings::firmware_request_nowarn`.
> > + pub fn request_nowarn(name: &CStr, dev: &Device) -> Result<Self> {
> > + Self::request_internal(name, dev, bindings::firmware_request_nowarn)
> > + }
> > +
> > + fn as_raw(&self) -> *mut bindings::firmware {
> > + self.0.as_ptr()
> > + }
> > +
> > + /// Returns the size of the requested firmware in bytes.
> > + pub fn size(&self) -> usize {
> > + // SAFETY: Safe by the type invariant.
> > + unsafe { (*self.as_raw()).size }
> > + }
> > +
> > + /// Returns the requested firmware as `&[u8]`.
> > + pub fn data(&self) -> &[u8] {
> > + // SAFETY: Safe by the type invariant. Additionally, `bindings::firmware` guarantees, if
>
> I would not write "Safe by ...", since it is important to know what is
> guaranteed by what. Instead I would write "self.as_raw() is valid by the
> type invariant.".
>
> > + // successfully requested, that `bindings::firmware::data` has a size of
> > + // `bindings::firmware::size` bytes.
> > + unsafe { core::slice::from_raw_parts((*self.as_raw()).data, self.size()) }
> > + }
> > +}
> > +
> > +impl Drop for Firmware {
> > + fn drop(&mut self) {
> > + // SAFETY: Safe by the type invariant.
>
> Ditto.
>
> ---
> Cheers,
> Benno
>
> > + unsafe { bindings::release_firmware(self.as_raw()) };
> > + }
> > +}
> > +
> > +// SAFETY: `Firmware` only holds a pointer to a C `struct firmware`, which is safe to be used from
> > +// any thread.
> > +unsafe impl Send for Firmware {}
> > +
> > +// SAFETY: `Firmware` only holds a pointer to a C `struct firmware`, references to which are safe to
> > +// be used from any thread.
> > +unsafe impl Sync for Firmware {}
> > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> > index dd1207f1a873..7707cb013ce9 100644
> > --- a/rust/kernel/lib.rs
> > +++ b/rust/kernel/lib.rs
> > @@ -30,6 +30,8 @@
> > mod build_assert;
> > pub mod device;
> > pub mod error;
> > +#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
> > +pub mod firmware;
> > pub mod init;
> > pub mod ioctl;
> > #[cfg(CONFIG_KUNIT)]
> > --
> > 2.45.1
> >
>
next prev parent reply other threads:[~2024-06-19 9:44 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-18 15:48 [PATCH v4 0/2] Rust abstractions for Device & Firmware Danilo Krummrich
2024-06-18 15:48 ` [PATCH v4 1/2] rust: add abstraction for struct device Danilo Krummrich
2024-06-19 8:53 ` Benno Lossin
2024-06-20 13:37 ` Gary Guo
2024-06-18 15:48 ` [PATCH v4 2/2] rust: add firmware abstractions Danilo Krummrich
2024-06-18 16:27 ` Boqun Feng
2024-06-19 8:58 ` Benno Lossin
2024-06-19 9:44 ` Danilo Krummrich [this message]
2024-06-19 10:43 ` Greg KH
2024-06-19 11:33 ` Danilo Krummrich
2024-06-20 13:36 ` Gary Guo
2024-06-20 13:43 ` Danilo Krummrich
2024-06-27 10:36 ` Gary Guo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZnKod6Wn5louhPu8@pollux \
--to=dakr@redhat.com \
--cc=a.hindborg@samsung.com \
--cc=airlied@gmail.com \
--cc=ajanulgu@redhat.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=fujita.tomonori@gmail.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lyude@redhat.com \
--cc=mcgrof@kernel.org \
--cc=ojeda@kernel.org \
--cc=pstanner@redhat.com \
--cc=rafael@kernel.org \
--cc=russ.weight@linux.dev \
--cc=rust-for-linux@vger.kernel.org \
--cc=wedsonaf@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.