1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
// 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, ffi, str::CStr};
use core::ptr::NonNull;
/// # Invariants
///
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
struct FwFunc(
unsafe extern "C" fn(
*mut *const bindings::firmware,
*const ffi::c_char,
*mut bindings::device,
) -> i32,
);
impl FwFunc {
fn request() -> Self {
Self(bindings::request_firmware)
}
fn request_nowarn() -> Self {
Self(bindings::firmware_request_nowarn)
}
}
/// 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`.
///
/// The `Firmware`'s backing buffer is not modified.
///
/// # Examples
///
/// ```no_run
/// # use kernel::{c_str, device::Device, firmware::Firmware};
///
/// # fn no_run() -> Result<(), Error> {
/// # // SAFETY: *NOT* safe, just for the example to get an `ARef<Device>` instance
/// # let dev = unsafe { Device::get_device(core::ptr::null_mut()) };
///
/// let fw = Firmware::request(c_str!("path/to/firmware.bin"), &dev)?;
/// let blob = fw.data();
///
/// # Ok(())
/// # }
/// ```
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.0(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, FwFunc::request())
}
/// 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, FwFunc::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: `self.as_raw()` is valid by the type invariant.
unsafe { (*self.as_raw()).size }
}
/// Returns the requested firmware as `&[u8]`.
pub fn data(&self) -> &[u8] {
// SAFETY: `self.as_raw()` is valid by the type invariant. Additionally,
// `bindings::firmware` guarantees, if 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: `self.as_raw()` is valid by the type invariant.
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 {}
/// Create firmware .modinfo entries.
///
/// This macro is the counterpart of the C macro `MODULE_FIRMWARE()`, but instead of taking a
/// simple string literals, which is already covered by the `firmware` field of
/// [`crate::prelude::module!`], it allows the caller to pass a builder type, based on the
/// [`ModInfoBuilder`], which can create the firmware modinfo strings in a more flexible way.
///
/// Drivers should extend the [`ModInfoBuilder`] with their own driver specific builder type.
///
/// The `builder` argument must be a type which implements the following function.
///
/// `const fn create(module_name: &'static CStr) -> ModInfoBuilder`
///
/// `create` should pass the `module_name` to the [`ModInfoBuilder`] and, with the help of
/// it construct the corresponding firmware modinfo.
///
/// Typically, such contracts would be enforced by a trait, however traits do not (yet) support
/// const functions.
///
/// # Example
///
/// ```
/// # mod module_firmware_test {
/// # use kernel::firmware;
/// # use kernel::prelude::*;
/// #
/// # struct MyModule;
/// #
/// # impl kernel::Module for MyModule {
/// # fn init(_module: &'static ThisModule) -> Result<Self> {
/// # Ok(Self)
/// # }
/// # }
/// #
/// #
/// struct Builder<const N: usize>;
///
/// impl<const N: usize> Builder<N> {
/// const DIR: &'static str = "vendor/chip/";
/// const FILES: [&'static str; 3] = [ "foo", "bar", "baz" ];
///
/// const fn create(module_name: &'static kernel::str::CStr) -> firmware::ModInfoBuilder<N> {
/// let mut builder = firmware::ModInfoBuilder::new(module_name);
///
/// let mut i = 0;
/// while i < Self::FILES.len() {
/// builder = builder.new_entry()
/// .push(Self::DIR)
/// .push(Self::FILES[i])
/// .push(".bin");
///
/// i += 1;
/// }
///
/// builder
/// }
/// }
///
/// module! {
/// type: MyModule,
/// name: "module_firmware_test",
/// author: "Rust for Linux",
/// description: "module_firmware! test module",
/// license: "GPL",
/// }
///
/// kernel::module_firmware!(Builder);
/// # }
/// ```
#[macro_export]
macro_rules! module_firmware {
// The argument is the builder type without the const generic, since it's deferred from within
// this macro. Hence, we can neither use `expr` nor `ty`.
($($builder:tt)*) => {
const _: () = {
const __MODULE_FIRMWARE_PREFIX: &'static $crate::str::CStr = if cfg!(MODULE) {
$crate::c_str!("")
} else {
<LocalModule as $crate::ModuleMetadata>::NAME
};
#[link_section = ".modinfo"]
#[used]
static __MODULE_FIRMWARE: [u8; $($builder)*::create(__MODULE_FIRMWARE_PREFIX)
.build_length()] = $($builder)*::create(__MODULE_FIRMWARE_PREFIX).build();
};
};
}
/// Builder for firmware module info.
///
/// [`ModInfoBuilder`] is a helper component to flexibly compose firmware paths strings for the
/// .modinfo section in const context.
///
/// Therefore the [`ModInfoBuilder`] provides the methods [`ModInfoBuilder::new_entry`] and
/// [`ModInfoBuilder::push`], where the latter is used to push path components and the former to
/// mark the beginning of a new path string.
///
/// [`ModInfoBuilder`] is meant to be used in combination with [`kernel::module_firmware!`].
///
/// The const generic `N` as well as the `module_name` parameter of [`ModInfoBuilder::new`] is an
/// internal implementation detail and supplied through the above macro.
pub struct ModInfoBuilder<const N: usize> {
buf: [u8; N],
n: usize,
module_name: &'static CStr,
}
impl<const N: usize> ModInfoBuilder<N> {
/// Create an empty builder instance.
pub const fn new(module_name: &'static CStr) -> Self {
Self {
buf: [0; N],
n: 0,
module_name,
}
}
const fn push_internal(mut self, bytes: &[u8]) -> Self {
let mut j = 0;
if N == 0 {
self.n += bytes.len();
return self;
}
while j < bytes.len() {
if self.n < N {
self.buf[self.n] = bytes[j];
}
self.n += 1;
j += 1;
}
self
}
/// Push an additional path component.
///
/// Append path components to the [`ModInfoBuilder`] instance. Paths need to be separated
/// with [`ModInfoBuilder::new_entry`].
///
/// # Example
///
/// ```
/// use kernel::firmware::ModInfoBuilder;
///
/// # const DIR: &str = "vendor/chip/";
/// # const fn no_run<const N: usize>(builder: ModInfoBuilder<N>) {
/// let builder = builder.new_entry()
/// .push(DIR)
/// .push("foo.bin")
/// .new_entry()
/// .push(DIR)
/// .push("bar.bin");
/// # }
/// ```
pub const fn push(self, s: &str) -> Self {
// Check whether there has been an initial call to `next_entry()`.
if N != 0 && self.n == 0 {
crate::build_error!("Must call next_entry() before push().");
}
self.push_internal(s.as_bytes())
}
const fn push_module_name(self) -> Self {
let mut this = self;
let module_name = this.module_name;
if !this.module_name.is_empty() {
this = this.push_internal(module_name.as_bytes_with_nul());
if N != 0 {
// Re-use the space taken by the NULL terminator and swap it with the '.' separator.
this.buf[this.n - 1] = b'.';
}
}
this
}
/// Prepare the [`ModInfoBuilder`] for the next entry.
///
/// This method acts as a separator between module firmware path entries.
///
/// Must be called before constructing a new entry with subsequent calls to
/// [`ModInfoBuilder::push`].
///
/// See [`ModInfoBuilder::push`] for an example.
pub const fn new_entry(self) -> Self {
self.push_internal(b"\0")
.push_module_name()
.push_internal(b"firmware=")
}
/// Build the byte array.
pub const fn build(self) -> [u8; N] {
// Add the final NULL terminator.
let this = self.push_internal(b"\0");
if this.n == N {
this.buf
} else {
crate::build_error!("Length mismatch.");
}
}
}
impl ModInfoBuilder<0> {
/// Return the length of the byte array to build.
pub const fn build_length(self) -> usize {
// Compensate for the NULL terminator added by `build`.
self.n + 1
}
}