mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-27 21:03:31 -04:00
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
...
311 lines
7.9 KiB
Rust
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>"
|
|
}
|
|
}
|