Files
linux/rust/kernel/lib.rs
Linus Torvalds 59e6295fac Merge tag 'driver-core-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core
Pull driver core updates from Danilo Krummrich:
 "container_of:

   - Apply typeof_member(), remove the local __mptr variable to
     eliminate variable shadowing warnings on nested container_of()
     calls, and remove unnecessary parentheses

  core:

   - Add driver name to probe debug print for initcall_debug

   - Avoid repeatedly printing the same 'Fixed dependency cycle' log

   - Unwind device_add() on attribute creation failure in
     attribute_container_add_class_device()

   - Remove statistics group if encryption group creation fails in
     transport_add_class_device()

  debugfs:

   - Fix lockdown check for mmap_prepare()

   - Warn if file creation failed due to uninitialized debugfs

  device property:

   - Implement fw_devlink support for software nodes by adding
     software_node_add_links(), which creates fwnode links from
     DEV_PROP_REF properties to enable automatic probe ordering. Add
     kunit-managed fwnode helpers and test coverage

   - Fix infinite loop in fwnode_for_each_child_node() when the
     secondary fwnode has more than one child. Add test cases

   - Fix out-of-bounds access in software_node_get_reference_args() when
     called with index -1 (UINT_MAX)

   - Refactor to use RAII approach with __free()

   - Add Bartosz Golaszewski as software node reviewer

  firmware loader:

   - Fix race where a sysfs fallback request can complete before being
     queued as pending, leading to a use-after-free on the next fallback
     request

   - Reject 0-size built-in firmware and fail the build on empty
     firmware files in CONFIG_EXTRA_FIRMWARE

  kobject:

   - Provide __KOBJ_ATTR() and __KOBJ_ATTR_RO/WO() initialization macros
     and allow the constification of kobject attributes, enabling them
     to reside in read-only memory

  platform:

   - Provide platform_device_set_of_node(), platform_device_set_fwnode(),
     and platform_device_set_of_node_from_dev() helpers that encapsulate
     firmware node reference counting for dynamically allocated platform
     devices

     Convert all in-tree users that manually assigned dev.of_node or
     dev.fwnode, fixing a pre-existing refcount bug in powermac. Switch
     to counting references of all firmware node types, not only OF
     nodes

   - Unify the release path for dynamically allocated platform devices
     by removing platform_device_release_full(). Amend the fwnode setter
     API contract to warn if a primary software node is overwritten. Add
     KUnit tests for correct software node removal on device
     unregistration

  Rust:

   - Auxiliary:
       - Add registration_data_with() closure-based API for invariant
         ForLt types

   - Debugfs:
       - Migrate BinaryWriter and BinaryReaderMut trait requirements
         from kernel::transmute traits to zerocopy traits

   - Device:
       - Add BoundInternal device context and InternalBoundContext trait
         for bus abstractions that need internal access to a bound
         device.
       - Make the lifetime on Core and CoreInternal invariant to prevent
         coercion to shorter lifetimes

   - Devres:
       - Fix race between concurrent revokers where the losing revoker
         could return before the winning revoker finished dropping the
         inner data, causing use-after-free.
       - Ensure revocation is complete before the device finishes
         unbinding by making the synchronization bidirectional.
       - Add DevresLt<F: ForLt>, a wrapper around Devres that shortens
         'static back to the caller's borrow scope. Implement ForLt and
         CovariantForLt for Bar, IoMem, and ExclusiveIoMem

   - Driver:
       - Switch from index-based to pointer-based device ID info lookup,
         storing static references in driver_data. Centralize device ID
         handling in device_id.rs, removing the open-coded ACPI/OF
         matching logic and duplicate ID table from driver.rs

   - I/O:
       - Make I/O regions typed (with a dynamically-sized Region type
         for the existing untyped case), create view types representing
         subregions of a mapped I/O region, and add io_project!() for
         safely creating subviews.
       - Split Io into a base trait (IoBase) and an extension trait (Io)
         with a blanket implementation, preventing implementers from
         overriding provided methods that unsafe code relies on.
       - Add a SysMem backend for shared system memory with volatile
         access, and make Coherent implement Io via an I/O view type.
         Add IoSysMap as sum type of Mmio and SysMem. Add copying
         methods (memcpy_{from,to}io()) and read_val()/write_val() for
         typed access.
       - Replace dma_read!()/dma_write!() with io_read!()/io_write!()
         for primitives and copying methods for aggregates; drop the old
         macros. Convert nova-core to use I/O projection.
       - Fix internal shortcut rule dispatch in the register!() macro,
         remove unused rule arguments, and use path fragments for alias
         destinations

   - IRQ:
       - Make irq::Registration compatible with lifetime-bound drivers
         by removing the 'static bound on Handler/ThreadedHandler and
         replacing Devres<RegistrationInner> with direct
         request_irq()/free_irq() calls. Handlers can now directly own
         lifetime-bound device resources

   - PCI:
       - Convert IrqVectorRegistration to a lifetime-annotated owning
         type, giving drivers explicit control over the allocation
         lifetime. IrqVector embeds a resolved IrqRequest, making the
         conversion infallible. Remove the redundant
         request_irq()/request_threaded_irq() wrappers from pci::Device.
       - Add pci_irq_type() C helper and expose it via irq_type() on
         IrqVectorRegistration and IrqVector, returning PCI_IRQ_MSIX,
         PCI_IRQ_MSI, or PCI_IRQ_INTX.
       - Mark pci::Device refcount methods inline

   - Serdev:
       - Add Rust abstractions for the serial device bus, including
         serdev::Driver trait, serdev::Device wrapping struct
         serdev_device, and serdev::Adapter implementing
         RegistrationOps. Includes a sample driver. Markus Probst takes
         over as serdev maintainer for both C and Rust code

   - Misc:
       - Split ForLt into a base trait (providing the Of<'a> GAT) and an
         unsafe CovariantForLt subtrait guaranteeing covariance,
         enabling invariant types (e.g. those containing Mutex<&'bound T>)
         to participate in the ForLt abstraction.
       - Fix Coherent read past EOF returning -ERANGE instead of zero.
       - Fix firmware example UB by avoiding null-pointer ARef

  misc:
   - Avoid iattr allocation in kernfs listxattr by using
     kernfs_iattrs_noalloc().
   - Unregister SoC bus on early device registration failure.
   - Remove unused DMA_FENCE_TRACE Kconfig symbol.
   - Fix /sys/module path in comment.
   - Refactor ISA bus init to remove nested blocks.
   - Remove redundant nodemask clears in numa_init().
   - Add kernel-doc for fwnode_operations and sys_soc.h, mark
     internal property data as private for kernel-doc, and add
     property.h/fwnode.h to driver-api infrastructure docs.
   - Add MAINTAINERS entry for sys_soc.h"

* tag 'driver-core-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core: (129 commits)
  rust: pci: expose the allocated interrupt type
  PCI: Add pci_irq_type() to query the allocated interrupt type
  rust: pci: remove request_irq() and request_threaded_irq() from Device
  rust: pci: resolve IRQ in index() and embed IrqRequest in IrqVector
  rust: pci: convert IrqVectorRegistration to a lifetime-managed owning type
  kernfs: avoid iattr allocation in listxattr
  rust: serdev: use ThisModule::as_ptr() instead of field access
  ACPI/IORT: use platform_device_set_fwnode()
  ACPI/APMT: use platform_device_set_fwnode()
  firmware_loader: do not queue completed sysfs fallback requests
  rust: pci: Mark Device refcount methods inline
  rust: irq: make Registration compatible with lifetime-bound drivers
  rust: net/phy: remove expansion from doc
  rust: dma: return zero for Coherent reads past EOF
  rust: io: register: use path fragment for alias destination
  rust: io: register: remove unused rule arguments
  rust: io: register: dispatch shortcut rules internally
  MAINTAINERS: add sys_soc.h to DRIVER CORE
  rust: debugfs: remove unsafe blocks from traits impl for Vec
  rust: debugfs: migrate debugfs traits requirements to zerocopy
  ...
2026-08-19 10:42:18 -07:00

311 lines
7.9 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_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>"
}
}