mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-27 17:35:18 -04:00
Pull fwctl updates from Jason Gunthorpe: - Support more commands in bnxt, this completes what they originally wanted to do - Rust bindings for fwctl. The Nova GPU is expected to use them next cycle * tag 'for-linus-fwctl' of git://git.kernel.org/pub/scm/linux/kernel/git/fwctl/fwctl: rust: introduce abstractions for fwctl fwctl/bnxt: Add DMA buffer support for HWRM commands bnxt_en: Update bnxt firmware spec
313 lines
8.0 KiB
Rust
313 lines
8.0 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
//! The `kernel` crate.
|
|
//!
|
|
//! This crate contains the kernel APIs that have been ported or wrapped for
|
|
//! usage by Rust code in the kernel and is shared by all of them.
|
|
//!
|
|
//! In other words, all the rest of the Rust code in the kernel (e.g. kernel
|
|
//! modules written in Rust) depends on [`core`] and this crate.
|
|
//!
|
|
//! If you need a kernel C API that is not ported or wrapped yet here, then
|
|
//! do so first instead of bypassing this crate.
|
|
|
|
#![no_std]
|
|
//
|
|
// Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
|
|
// the unstable features in use.
|
|
//
|
|
// Stable since Rust 1.87.0.
|
|
#![feature(unsigned_is_multiple_of)]
|
|
//
|
|
// Stable since Rust 1.89.0.
|
|
#![feature(generic_arg_infer)]
|
|
//
|
|
// Expected to become stable.
|
|
#![feature(arbitrary_self_types)]
|
|
#![feature(derive_coerce_pointee)]
|
|
//
|
|
// To be determined.
|
|
#![feature(used_with_arg)]
|
|
//
|
|
// `feature(file_with_nul)` is stable since Rust 1.92.0. Before Rust 1.89.0, it did not exist, so
|
|
// enable it conditionally.
|
|
#![cfg_attr(CONFIG_RUSTC_HAS_FILE_WITH_NUL, feature(file_with_nul))]
|
|
|
|
// Ensure conditional compilation based on the kernel configuration works;
|
|
// otherwise we may silently break things like initcall handling.
|
|
#[cfg(not(CONFIG_RUST))]
|
|
compile_error!("Missing kernel configuration for conditional compilation");
|
|
|
|
// Allow proc-macros to refer to `::kernel` inside the `kernel` crate (this crate).
|
|
extern crate self as kernel;
|
|
|
|
pub use ffi;
|
|
|
|
pub mod acpi;
|
|
pub mod alloc;
|
|
#[cfg(CONFIG_AUXILIARY_BUS)]
|
|
pub mod auxiliary;
|
|
pub mod bitfield;
|
|
pub mod bitmap;
|
|
pub mod bits;
|
|
#[cfg(CONFIG_BLOCK)]
|
|
pub mod block;
|
|
pub mod bug;
|
|
pub mod build_assert;
|
|
pub mod clk;
|
|
#[cfg(CONFIG_CONFIGFS_FS)]
|
|
pub mod configfs;
|
|
pub mod cpu;
|
|
#[cfg(CONFIG_CPU_FREQ)]
|
|
pub mod cpufreq;
|
|
pub mod cpumask;
|
|
pub mod cred;
|
|
pub mod debugfs;
|
|
pub mod device;
|
|
pub mod device_id;
|
|
pub mod devres;
|
|
pub mod dma;
|
|
pub mod driver;
|
|
#[cfg(CONFIG_DRM = "y")]
|
|
pub mod drm;
|
|
pub mod error;
|
|
pub mod faux;
|
|
#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
|
|
pub mod firmware;
|
|
pub mod fmt;
|
|
pub mod fs;
|
|
#[cfg(CONFIG_RUST_FWCTL_ABSTRACTIONS)]
|
|
pub mod fwctl;
|
|
#[cfg(CONFIG_GPU_BUDDY = "y")]
|
|
pub mod gpu;
|
|
#[cfg(CONFIG_I2C = "y")]
|
|
pub mod i2c;
|
|
pub mod id_pool;
|
|
#[doc(hidden)]
|
|
pub mod impl_flags;
|
|
pub mod init;
|
|
pub mod interop;
|
|
pub mod interrupt;
|
|
pub mod io;
|
|
pub mod ioctl;
|
|
pub mod iommu;
|
|
pub mod iov;
|
|
pub mod irq;
|
|
pub mod jump_label;
|
|
#[cfg(CONFIG_KUNIT)]
|
|
pub mod kunit;
|
|
pub mod list;
|
|
pub mod maple_tree;
|
|
pub mod miscdevice;
|
|
pub mod mm;
|
|
pub mod module;
|
|
pub mod module_param;
|
|
#[cfg(CONFIG_NET)]
|
|
pub mod net;
|
|
pub mod num;
|
|
pub mod of;
|
|
#[cfg(CONFIG_PM_OPP)]
|
|
pub mod opp;
|
|
pub mod page;
|
|
#[cfg(CONFIG_PCI)]
|
|
pub mod pci;
|
|
pub mod pid_namespace;
|
|
pub mod platform;
|
|
pub mod prelude;
|
|
pub mod print;
|
|
pub mod processor;
|
|
pub mod ptr;
|
|
#[cfg(CONFIG_RUST_PWM_ABSTRACTIONS)]
|
|
pub mod pwm;
|
|
pub mod rbtree;
|
|
pub mod regulator;
|
|
pub mod revocable;
|
|
pub mod safety;
|
|
pub mod scatterlist;
|
|
pub mod security;
|
|
pub mod seq_file;
|
|
#[cfg(CONFIG_RUST_SERIAL_DEV_BUS_ABSTRACTIONS)]
|
|
pub mod serdev;
|
|
pub mod sizes;
|
|
#[cfg(CONFIG_SOC_BUS)]
|
|
pub mod soc;
|
|
#[doc(hidden)]
|
|
pub mod std_vendor;
|
|
pub mod str;
|
|
pub mod sync;
|
|
pub mod task;
|
|
pub mod time;
|
|
pub mod tracepoint;
|
|
pub mod transmute;
|
|
pub mod types;
|
|
pub mod uaccess;
|
|
#[cfg(CONFIG_USB = "y")]
|
|
pub mod usb;
|
|
pub mod workqueue;
|
|
pub mod xarray;
|
|
|
|
#[doc(hidden)]
|
|
pub use bindings;
|
|
pub use macros;
|
|
pub use module::{
|
|
InPlaceModule,
|
|
Module,
|
|
ModuleMetadata,
|
|
ThisModule, //
|
|
};
|
|
pub use uapi;
|
|
|
|
/// Prefix to appear before log messages printed from within the `kernel` crate.
|
|
const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
|
|
|
|
/// Dummy module type for `#[vtable]` `impl` blocks within the `kernel` crate (e.g. KUnit tests).
|
|
// The `allow` is needed since it may be unused (e.g. KUnit tests may be disabled).
|
|
#[allow(dead_code)]
|
|
struct LocalModule;
|
|
|
|
impl ModuleMetadata for LocalModule {
|
|
const NAME: &'static str::CStr = c"rust_kernel";
|
|
|
|
const THIS_MODULE: ThisModule = {
|
|
// SAFETY: `try_module_get`/`module_put` handle null module pointers gracefully.
|
|
unsafe { ThisModule::from_ptr(core::ptr::null_mut()) }
|
|
};
|
|
}
|
|
|
|
#[cfg(not(testlib))]
|
|
#[panic_handler]
|
|
fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
|
|
pr_emerg!("{}\n", info);
|
|
// SAFETY: FFI call.
|
|
unsafe { bindings::BUG() };
|
|
}
|
|
|
|
/// Produces a pointer to an object from a pointer to one of its fields.
|
|
///
|
|
/// If you encounter a type mismatch due to the [`Opaque`] type, then use [`Opaque::cast_into`] or
|
|
/// [`Opaque::cast_from`] to resolve the mismatch.
|
|
///
|
|
/// [`Opaque`]: crate::types::Opaque
|
|
/// [`Opaque::cast_into`]: crate::types::Opaque::cast_into
|
|
/// [`Opaque::cast_from`]: crate::types::Opaque::cast_from
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// The pointer passed to this macro, and the pointer returned by this macro, must both be in
|
|
/// bounds of the same allocation.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use kernel::container_of;
|
|
/// struct Test {
|
|
/// a: u64,
|
|
/// b: u32,
|
|
/// }
|
|
///
|
|
/// let test = Test { a: 10, b: 20 };
|
|
/// let b_ptr: *const _ = &test.b;
|
|
/// // SAFETY: The pointer points at the `b` field of a `Test`, so the resulting pointer will be
|
|
/// // in-bounds of the same allocation as `b_ptr`.
|
|
/// let test_alias = unsafe { container_of!(b_ptr, Test, b) };
|
|
/// assert!(core::ptr::eq(&test, test_alias));
|
|
/// ```
|
|
#[macro_export]
|
|
macro_rules! container_of {
|
|
($field_ptr:expr, $Container:ty, $($fields:tt)*) => {{
|
|
let offset: usize = ::core::mem::offset_of!($Container, $($fields)*);
|
|
let field_ptr = $field_ptr;
|
|
let container_ptr = field_ptr.byte_sub(offset).cast::<$Container>();
|
|
$crate::assert_same_type(field_ptr, (&raw const (*container_ptr).$($fields)*).cast_mut());
|
|
container_ptr
|
|
}}
|
|
}
|
|
|
|
/// Helper for [`container_of!`].
|
|
#[doc(hidden)]
|
|
pub fn assert_same_type<T>(_: T, _: T) {}
|
|
|
|
/// Helper for `.rs.S` files.
|
|
#[doc(hidden)]
|
|
#[macro_export]
|
|
macro_rules! concat_literals {
|
|
($( $asm:literal )* ) => {
|
|
::core::concat!($($asm),*)
|
|
};
|
|
}
|
|
|
|
/// Wrapper around `asm!` configured for use in the kernel.
|
|
///
|
|
/// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!`
|
|
/// syntax.
|
|
// For x86, `asm!` uses intel syntax by default, but we want to use at&t syntax in the kernel.
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
#[macro_export]
|
|
macro_rules! asm {
|
|
($($asm:expr),* ; $($rest:tt)*) => {
|
|
::core::arch::asm!( $($asm)*, options(att_syntax), $($rest)* )
|
|
};
|
|
}
|
|
|
|
/// Wrapper around `asm!` configured for use in the kernel.
|
|
///
|
|
/// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!`
|
|
/// syntax.
|
|
// For non-x86 arches we just pass through to `asm!`.
|
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
|
#[macro_export]
|
|
macro_rules! asm {
|
|
($($asm:expr),* ; $($rest:tt)*) => {
|
|
::core::arch::asm!( $($asm)*, $($rest)* )
|
|
};
|
|
}
|
|
|
|
/// Gets the C string file name of a [`Location`].
|
|
///
|
|
/// If `Location::file_as_c_str()` is not available, returns a string that warns about it.
|
|
///
|
|
/// [`Location`]: core::panic::Location
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use kernel::file_from_location;
|
|
///
|
|
/// #[track_caller]
|
|
/// fn foo() {
|
|
/// let caller = core::panic::Location::caller();
|
|
///
|
|
/// // Output:
|
|
/// // - A path like "rust/kernel/example.rs" if `file_as_c_str()` is available.
|
|
/// // - "<Location::file_as_c_str() not supported>" otherwise.
|
|
/// let caller_file = file_from_location(caller);
|
|
///
|
|
/// // Prints out the message with caller's file name.
|
|
/// pr_info!("foo() called in file {caller_file:?}\n");
|
|
///
|
|
/// # if cfg!(CONFIG_RUSTC_HAS_FILE_WITH_NUL) {
|
|
/// # assert_eq!(Ok(caller.file()), caller_file.to_str());
|
|
/// # }
|
|
/// }
|
|
///
|
|
/// # foo();
|
|
/// ```
|
|
#[inline]
|
|
pub fn file_from_location<'a>(loc: &'a core::panic::Location<'a>) -> &'a core::ffi::CStr {
|
|
#[cfg(CONFIG_RUSTC_HAS_FILE_AS_C_STR)]
|
|
{
|
|
loc.file_as_c_str()
|
|
}
|
|
|
|
#[cfg(all(CONFIG_RUSTC_HAS_FILE_WITH_NUL, not(CONFIG_RUSTC_HAS_FILE_AS_C_STR)))]
|
|
{
|
|
loc.file_with_nul()
|
|
}
|
|
|
|
#[cfg(not(CONFIG_RUSTC_HAS_FILE_WITH_NUL))]
|
|
{
|
|
let _ = loc;
|
|
c"<Location::file_as_c_str() not supported>"
|
|
}
|
|
}
|