mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
rust: firmware: add request_into_buf()
Add request_into_buf(), a Rust wrapper around the request_firmware_into_buf() function. This variant loads the firmware image directly into a caller-provided buffer rather than a kernel-allocated one. Signed-off-by: Timur Tabi <ttabi@nvidia.com> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Tested-by: Alexandre Courbot <acourbot@nvidia.com> Link: https://patch.msgid.link/20260731201017.2580713-3-ttabi@nvidia.com [ Declare fw as *const to match the FFI out-parameter type and pass &raw mut directly, removing the redundant cast chain. - Danilo ] Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
parent
60782beb11
commit
e6c2c62655
|
|
@ -7,9 +7,9 @@
|
|||
use crate::{
|
||||
bindings,
|
||||
device::Device,
|
||||
error::Error,
|
||||
error::Result,
|
||||
error::to_result,
|
||||
ffi,
|
||||
prelude::*,
|
||||
str::{CStr, CStrExt as _},
|
||||
};
|
||||
use core::ptr::NonNull;
|
||||
|
|
@ -120,6 +120,48 @@ fn drop(&mut self) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Load firmware directly into the caller-provided `buf`.
|
||||
///
|
||||
/// On success the firmware image has been copied into `buf`; the caller accesses the data
|
||||
/// through `buf` itself.
|
||||
///
|
||||
/// This is intentionally a stand-alone function rather than a `Firmware` constructor. For
|
||||
/// the `into_buf` path, the firmware data lives in the caller's `buf`, not in a
|
||||
/// kernel-owned buffer, so returning a `Firmware` would expose `Firmware::data()` as a
|
||||
/// second handle aliasing `buf` (and `release_firmware()` does not free `buf` anyway).
|
||||
pub fn request_into_buf(name: &CStr, dev: &Device, buf: &mut [u8]) -> Result {
|
||||
// `as_mut_ptr()` on an empty slice returns a non-NULL pointer to
|
||||
// memory which the loader does not own. Passing that pointer with `size == 0`
|
||||
// makes the loader believe that it is buffer it allocated itself, so when
|
||||
// `release_firmware()` is called, it will vfree the pointer and trigger a
|
||||
// bug. Reject empty slices to avoid this situation.
|
||||
if buf.is_empty() {
|
||||
return Err(EINVAL);
|
||||
}
|
||||
|
||||
let mut fw: *const bindings::firmware = core::ptr::null();
|
||||
|
||||
// SAFETY: `&raw mut fw` is a valid pointer to a NULL initialized `bindings::firmware` pointer.
|
||||
// `name` and `dev` are valid as by their type invariants. `buf` is a valid writable
|
||||
// buffer of `buf.len()` bytes.
|
||||
to_result(unsafe {
|
||||
bindings::request_firmware_into_buf(
|
||||
&raw mut fw,
|
||||
name.as_char_ptr(),
|
||||
dev.as_raw(),
|
||||
buf.as_mut_ptr().cast(),
|
||||
buf.len(),
|
||||
)
|
||||
})?;
|
||||
|
||||
// The firmware bytes are now in `buf`, which the caller owns, so we don't need
|
||||
// the kernel to hang on to it any more.
|
||||
// SAFETY: `fw` is a valid pointer returned by `request_firmware_into_buf`.
|
||||
unsafe { bindings::release_firmware(fw) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 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 {}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user