summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clippy.toml12
-rw-r--r--.gitignore4
-rw-r--r--Documentation/process/changes.rst4
-rw-r--r--Documentation/rust/general-information.rst4
-rw-r--r--Documentation/rust/quick-start.rst52
-rw-r--r--MAINTAINERS1
-rw-r--r--Makefile21
-rw-r--r--arch/Kconfig3
-rw-r--r--arch/arm64/Kconfig8
-rw-r--r--arch/riscv/Kconfig3
-rw-r--r--drivers/android/binder/Makefile3
-rw-r--r--drivers/android/binder/page_range.rs6
-rw-r--r--drivers/android/binder/page_range_helper.c24
-rw-r--r--drivers/android/binder/page_range_helper.h15
-rw-r--r--drivers/android/binder/rust_binder_main.rs2
-rw-r--r--drivers/gpu/drm/tyr/driver.rs12
-rw-r--r--drivers/gpu/nova-core/gsp/cmdq.rs6
-rw-r--r--drivers/gpu/nova-core/gsp/fw/r570_144.rs3
-rw-r--r--drivers/pwm/pwm_th1520.rs15
-rw-r--r--init/Kconfig30
-rw-r--r--lib/Kconfig.debug17
-rw-r--r--rust/Makefile69
-rw-r--r--rust/bindgen_parameters8
-rw-r--r--rust/bindings/bindings_helper.h1
-rw-r--r--rust/bindings/lib.rs5
-rw-r--r--rust/exports.c5
-rw-r--r--rust/helpers/clk.c24
-rw-r--r--rust/helpers/helpers.c29
-rw-r--r--rust/helpers/jump_label.c2
-rw-r--r--rust/kernel/alloc/allocator/iter.rs8
-rw-r--r--rust/kernel/alloc/kbox.rs29
-rw-r--r--rust/kernel/alloc/kvec/errors.rs3
-rw-r--r--rust/kernel/block/mq/gen_disk.rs4
-rw-r--r--rust/kernel/build_assert.rs183
-rw-r--r--rust/kernel/clk.rs7
-rw-r--r--rust/kernel/error.rs37
-rw-r--r--rust/kernel/i2c.rs13
-rw-r--r--rust/kernel/lib.rs38
-rw-r--r--rust/kernel/list.rs22
-rw-r--r--rust/kernel/list/arc.rs23
-rw-r--r--rust/kernel/list/arc_field.rs1
-rw-r--r--rust/kernel/list/impl_list_item_mod.rs3
-rw-r--r--rust/kernel/num/bounded.rs24
-rw-r--r--rust/kernel/prelude.rs110
-rw-r--r--rust/kernel/ptr.rs42
-rw-r--r--rust/kernel/sizes.rs172
-rw-r--r--rust/kernel/slice.rs49
-rw-r--r--rust/kernel/static_assert.rs39
-rw-r--r--rust/kernel/str.rs27
-rw-r--r--rust/kernel/sync/arc.rs21
-rw-r--r--rust/kernel/task.rs7
-rw-r--r--rust/kernel/time.rs32
-rw-r--r--rust/kernel/time/hrtimer.rs336
-rw-r--r--rust/kernel/transmute.rs35
-rw-r--r--rust/kernel/types.rs2
-rw-r--r--rust/kernel/usb.rs6
-rw-r--r--rust/kernel/xarray.rs1
-rw-r--r--rust/macros/helpers.rs1
-rw-r--r--rust/macros/kunit.rs9
-rw-r--r--rust/macros/lib.rs3
-rw-r--r--rust/macros/module.rs9
-rw-r--r--rust/pin-init/README.md3
-rw-r--r--rust/pin-init/examples/big_struct_in_place.rs3
-rw-r--r--rust/pin-init/examples/linked_list.rs3
-rw-r--r--rust/pin-init/examples/mutex.rs3
-rw-r--r--rust/pin-init/examples/pthread_mutex.rs3
-rw-r--r--rust/pin-init/examples/static_init.rs3
-rw-r--r--rust/pin-init/internal/src/init.rs14
-rw-r--r--rust/pin-init/internal/src/lib.rs2
-rw-r--r--rust/pin-init/src/lib.rs73
-rw-r--r--rust/uapi/lib.rs5
-rw-r--r--scripts/Makefile.build15
-rwxr-xr-xscripts/generate_rust_analyzer.py298
-rwxr-xr-xscripts/min-tool-version.sh4
-rwxr-xr-xscripts/rust_is_available.sh36
-rw-r--r--scripts/rust_is_available_bindgen_0_66.h2
-rw-r--r--scripts/rust_is_available_bindgen_libclang_concat.h3
-rwxr-xr-xscripts/rust_is_available_test.py58
78 files changed, 1391 insertions, 821 deletions
diff --git a/.clippy.toml b/.clippy.toml
index 137f41d203de..b0a78cc8be20 100644
--- a/.clippy.toml
+++ b/.clippy.toml
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-msrv = "1.78.0"
+msrv = "1.85.0"
check-private-items = true
@@ -9,3 +9,13 @@ disallowed-macros = [
# it here, see: https://github.com/rust-lang/rust-clippy/issues/11303.
{ path = "kernel::dbg", reason = "the `dbg!` macro is intended as a debugging tool", allow-invalid = true },
]
+
+[[disallowed-methods]]
+path = "core::ffi::CStr::as_ptr"
+replacement = "kernel::prelude::CStrExt::as_char_ptr"
+reason = "kernel's `char` is always unsigned, use `as_char_ptr` instead"
+
+[[disallowed-methods]]
+path = "core::ffi::CStr::from_ptr"
+replacement = "kernel::prelude::CStrExt::from_char_ptr"
+reason = "kernel's `char` is always unsigned, use `from_char_ptr` instead"
diff --git a/.gitignore b/.gitignore
index 3a7241c941f5..3044b9590f05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@
.*
*.a
*.asn1.[ch]
+*.bc
*.bin
*.bz2
*.c.[012]*.*
@@ -184,3 +185,6 @@ sphinx_*/
# Rust analyzer configuration
/rust-project.json
+
+# bc language scripts (not LLVM bitcode)
+!kernel/time/timeconst.bc
diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst
index 6b373e193548..84156d031365 100644
--- a/Documentation/process/changes.rst
+++ b/Documentation/process/changes.rst
@@ -31,8 +31,8 @@ you probably needn't concern yourself with pcmciautils.
====================== =============== ========================================
GNU C 8.1 gcc --version
Clang/LLVM (optional) 15.0.0 clang --version
-Rust (optional) 1.78.0 rustc --version
-bindgen (optional) 0.65.1 bindgen --version
+Rust (optional) 1.85.0 rustc --version
+bindgen (optional) 0.71.1 bindgen --version
GNU make 4.0 make --version
bash 4.2 bash --version
binutils 2.30 ld -v
diff --git a/Documentation/rust/general-information.rst b/Documentation/rust/general-information.rst
index 6146b49b6a98..09234bed272c 100644
--- a/Documentation/rust/general-information.rst
+++ b/Documentation/rust/general-information.rst
@@ -157,5 +157,5 @@ numerical comparisons, one may define a new Kconfig symbol:
.. code-block:: kconfig
- config RUSTC_VERSION_MIN_107900
- def_bool y if RUSTC_VERSION >= 107900
+ config RUSTC_HAS_SPAN_FILE
+ def_bool RUSTC_VERSION >= 108800
diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst
index 152289f0bed2..a6ec3fa94d33 100644
--- a/Documentation/rust/quick-start.rst
+++ b/Documentation/rust/quick-start.rst
@@ -57,8 +57,8 @@ of the box, e.g.::
Gentoo Linux
************
-Gentoo Linux (and especially the testing branch) provides recent Rust releases
-and thus it should generally work out of the box, e.g.::
+Gentoo Linux provides recent Rust releases and thus it should generally work out
+of the box, e.g.::
USE='rust-src rustfmt clippy' emerge dev-lang/rust dev-util/bindgen
@@ -68,8 +68,8 @@ and thus it should generally work out of the box, e.g.::
Nix
***
-Nix (unstable channel) provides recent Rust releases and thus it should
-generally work out of the box, e.g.::
+Nix provides recent Rust releases and thus it should generally work out of the
+box, e.g.::
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
@@ -84,16 +84,13 @@ openSUSE
openSUSE Slowroll and openSUSE Tumbleweed provide recent Rust releases and thus
they should generally work out of the box, e.g.::
- zypper install rust rust1.79-src rust-bindgen clang
+ zypper install rust rust-src rust-bindgen clang
Ubuntu
******
-25.04
-~~~~~
-
-The latest Ubuntu releases provide recent Rust releases and thus they should
+Ubuntu 25.10 and 26.04 LTS provide recent Rust releases and thus they should
generally work out of the box, e.g.::
apt install rustc rust-src bindgen rustfmt rust-clippy
@@ -112,33 +109,33 @@ Though Ubuntu 24.04 LTS and older versions still provide recent Rust
releases, they require some additional configuration to be set, using
the versioned packages, e.g.::
- apt install rustc-1.80 rust-1.80-src bindgen-0.65 rustfmt-1.80 \
- rust-1.80-clippy
- ln -s /usr/lib/rust-1.80/bin/rustfmt /usr/bin/rustfmt-1.80
- ln -s /usr/lib/rust-1.80/bin/clippy-driver /usr/bin/clippy-driver-1.80
+ apt install rustc-1.85 rust-1.85-src bindgen-0.71 rustfmt-1.85 \
+ rust-1.85-clippy
+ ln -s /usr/lib/rust-1.85/bin/rustfmt /usr/bin/rustfmt-1.85
+ ln -s /usr/lib/rust-1.85/bin/clippy-driver /usr/bin/clippy-driver-1.85
None of these packages set their tools as defaults; therefore they should be
specified explicitly, e.g.::
- make LLVM=1 RUSTC=rustc-1.80 RUSTDOC=rustdoc-1.80 RUSTFMT=rustfmt-1.80 \
- CLIPPY_DRIVER=clippy-driver-1.80 BINDGEN=bindgen-0.65
+ make LLVM=1 RUSTC=rustc-1.85 RUSTDOC=rustdoc-1.85 RUSTFMT=rustfmt-1.85 \
+ CLIPPY_DRIVER=clippy-driver-1.85 BINDGEN=bindgen-0.71
-Alternatively, modify the ``PATH`` variable to place the Rust 1.80 binaries
+Alternatively, modify the ``PATH`` variable to place the Rust 1.85 binaries
first and set ``bindgen`` as the default, e.g.::
- PATH=/usr/lib/rust-1.80/bin:$PATH
+ PATH=/usr/lib/rust-1.85/bin:$PATH
update-alternatives --install /usr/bin/bindgen bindgen \
- /usr/bin/bindgen-0.65 100
- update-alternatives --set bindgen /usr/bin/bindgen-0.65
+ /usr/bin/bindgen-0.71 100
+ update-alternatives --set bindgen /usr/bin/bindgen-0.71
-``RUST_LIB_SRC`` needs to be set when using the versioned packages, e.g.::
+``RUST_LIB_SRC`` may need to be set when using the versioned packages, e.g.::
- RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.80 --version | cut -d' ' -f2)/library
+ RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.85 --version | cut -d' ' -f2)/library
For convenience, ``RUST_LIB_SRC`` can be exported to the global environment.
-In addition, ``bindgen-0.65`` is available in newer releases (24.04 LTS and
-24.10), but it may not be available in older ones (20.04 LTS and 22.04 LTS),
+In addition, ``bindgen-0.71`` is available in newer releases (24.04 LTS),
+but it may not be available in older ones (20.04 LTS and 22.04 LTS),
thus ``bindgen`` may need to be built manually (please see below).
@@ -355,12 +352,3 @@ Hacking
To dive deeper, take a look at the source code of the samples
at ``samples/rust/``, the Rust support code under ``rust/`` and
the ``Rust hacking`` menu under ``Kernel hacking``.
-
-If GDB/Binutils is used and Rust symbols are not getting demangled, the reason
-is the toolchain does not support Rust's new v0 mangling scheme yet.
-There are a few ways out:
-
-- Install a newer release (GDB >= 10.2, Binutils >= 2.36).
-
-- Some versions of GDB (e.g. vanilla GDB 10.1) are able to use
- the pre-demangled names embedded in the debug info (``CONFIG_DEBUG_INFO``).
diff --git a/MAINTAINERS b/MAINTAINERS
index d1cc0e12fe1f..cff10617372e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23166,6 +23166,7 @@ C: zulip://rust-for-linux.zulipchat.com
P: https://rust-for-linux.com/contributing
T: git https://github.com/Rust-for-Linux/linux.git rust-next
F: .clippy.toml
+F: .rustfmt.toml
F: Documentation/rust/
F: include/trace/events/rust_sample.h
F: rust/
diff --git a/Makefile b/Makefile
index 36d0a32fbe49..2345552219e9 100644
--- a/Makefile
+++ b/Makefile
@@ -487,6 +487,7 @@ export rust_common_flags := --edition=2021 \
-Wclippy::as_underscore \
-Wclippy::cast_lossless \
-Wclippy::ignored_unit_patterns \
+ -Aclippy::incompatible_msrv \
-Wclippy::mut_mut \
-Wclippy::needless_bitwise_bool \
-Aclippy::needless_lifetimes \
@@ -495,6 +496,7 @@ export rust_common_flags := --edition=2021 \
-Wclippy::ptr_cast_constness \
-Wclippy::ref_as_ptr \
-Wclippy::undocumented_unsafe_blocks \
+ -Aclippy::uninlined_format_args \
-Wclippy::unnecessary_safety_comment \
-Wclippy::unnecessary_safety_doc \
-Wrustdoc::missing_crate_level_docs \
@@ -505,7 +507,7 @@ KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \
KBUILD_HOSTCXXFLAGS := -Wall -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS) \
-I $(srctree)/scripts/include
KBUILD_HOSTRUSTFLAGS := $(rust_common_flags) -O -Cstrip=debuginfo \
- -Zallow-features= $(HOSTRUSTFLAGS)
+ -Zallow-features=
KBUILD_HOSTLDFLAGS := $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS)
KBUILD_HOSTLDLIBS := $(HOST_LFS_LIBS) $(HOSTLDLIBS)
KBUILD_PROCMACROLDFLAGS := $(or $(PROCMACROLDFLAGS),$(KBUILD_HOSTLDFLAGS))
@@ -516,6 +518,7 @@ ifneq ($(LLVM),)
CC = $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
LD = $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX)
AR = $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)
+LLVM_LINK = $(LLVM_PREFIX)llvm-link$(LLVM_SUFFIX)
NM = $(LLVM_PREFIX)llvm-nm$(LLVM_SUFFIX)
OBJCOPY = $(LLVM_PREFIX)llvm-objcopy$(LLVM_SUFFIX)
OBJDUMP = $(LLVM_PREFIX)llvm-objdump$(LLVM_SUFFIX)
@@ -629,7 +632,7 @@ export RUSTC_BOOTSTRAP := 1
export CLIPPY_CONF_DIR := $(srctree)
export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG
-export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN
+export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN LLVM_LINK
export HOSTRUSTC KBUILD_HOSTRUSTFLAGS
export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
@@ -834,6 +837,20 @@ endif # CONFIG_TRACEPOINTS
export WARN_ON_UNUSED_TRACEPOINTS
+# Per-version Rust flags. These are like `rust_common_flags`, but may
+# depend on the Rust compiler version (e.g. using `rustc-min-version`).
+#
+# `-Aclippy::precedence`: the lint was extended in Rust 1.85.0 to
+# include bitmasking and shift operations. However, because it generated
+# many hits, in Rust 1.86.0 it was split into a new `precedence_bits`
+# lint which is not enabled by default.
+rust_common_flags_per_version := \
+ $(if $(call rustc-min-version,108600),,-Aclippy::precedence)
+
+rust_common_flags += $(rust_common_flags_per_version)
+KBUILD_HOSTRUSTFLAGS += $(rust_common_flags_per_version) $(HOSTRUSTFLAGS)
+KBUILD_RUSTFLAGS += $(rust_common_flags_per_version)
+
include $(srctree)/arch/$(SRCARCH)/Makefile
ifdef need-config
diff --git a/arch/Kconfig b/arch/Kconfig
index 102ddbd4298e..84089e80584b 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -968,10 +968,9 @@ config HAVE_CFI_ICALL_NORMALIZE_INTEGERS
config HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
def_bool y
depends on HAVE_CFI_ICALL_NORMALIZE_INTEGERS
- depends on RUSTC_VERSION >= 107900
depends on ARM64 || X86_64
# With GCOV/KASAN we need this fix: https://github.com/rust-lang/rust/pull/129373
- depends on (RUSTC_LLVM_VERSION >= 190103 && RUSTC_VERSION >= 108200) || \
+ depends on RUSTC_LLVM_VERSION >= 190103 || \
(!GCOV_KERNEL && !KASAN_GENERIC && !KASAN_SW_TAGS)
config CFI_PERMISSIVE
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9ea19b74b6c3..4de630e398ca 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -292,14 +292,6 @@ config ARM64
config RUSTC_SUPPORTS_ARM64
def_bool y
depends on CPU_LITTLE_ENDIAN
- # Shadow call stack is only supported on certain rustc versions.
- #
- # When using the UNWIND_PATCH_PAC_INTO_SCS option, rustc version 1.80+ is
- # required due to use of the -Zfixed-x18 flag.
- #
- # Otherwise, rustc version 1.82+ is required due to use of the
- # -Zsanitizer=shadow-call-stack flag.
- depends on !SHADOW_CALL_STACK || RUSTC_VERSION >= 108200 || RUSTC_VERSION >= 108000 && UNWIND_PATCH_PAC_INTO_SCS
config CLANG_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS
def_bool CC_IS_CLANG
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 90c531e6abf5..ddc534402400 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -232,9 +232,6 @@ config RISCV
config RUSTC_SUPPORTS_RISCV
def_bool y
depends on 64BIT
- # Shadow call stack requires rustc version 1.82+ due to use of the
- # -Zsanitizer=shadow-call-stack flag.
- depends on !SHADOW_CALL_STACK || RUSTC_VERSION >= 108200
config CLANG_SUPPORTS_DYNAMIC_FTRACE
def_bool CC_IS_CLANG
diff --git a/drivers/android/binder/Makefile b/drivers/android/binder/Makefile
index 09eabb527fa0..7e0cd9782a8b 100644
--- a/drivers/android/binder/Makefile
+++ b/drivers/android/binder/Makefile
@@ -5,5 +5,4 @@ obj-$(CONFIG_ANDROID_BINDER_IPC_RUST) += rust_binder.o
rust_binder-y := \
rust_binder_main.o \
rust_binderfs.o \
- rust_binder_events.o \
- page_range_helper.o
+ rust_binder_events.o
diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs
index b57e0c7ba3f1..60e20fcf7c94 100644
--- a/drivers/android/binder/page_range.rs
+++ b/drivers/android/binder/page_range.rs
@@ -683,15 +683,15 @@ unsafe extern "C" fn rust_shrink_scan(
unsafe {
bindings::list_lru_walk(
list_lru,
- Some(bindings::rust_shrink_free_page_wrap),
+ Some(rust_shrink_free_page),
ptr::null_mut(),
nr_to_scan,
)
}
}
-const LRU_SKIP: bindings::lru_status = bindings::lru_status_LRU_SKIP;
-const LRU_REMOVED_ENTRY: bindings::lru_status = bindings::lru_status_LRU_REMOVED_RETRY;
+const LRU_SKIP: bindings::lru_status = bindings::lru_status::LRU_SKIP;
+const LRU_REMOVED_ENTRY: bindings::lru_status = bindings::lru_status::LRU_REMOVED_RETRY;
/// # Safety
/// Called by the shrinker.
diff --git a/drivers/android/binder/page_range_helper.c b/drivers/android/binder/page_range_helper.c
deleted file mode 100644
index 496887723ee0..000000000000
--- a/drivers/android/binder/page_range_helper.c
+++ /dev/null
@@ -1,24 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-/* C helper for page_range.rs to work around a CFI violation.
- *
- * Bindgen currently pretends that `enum lru_status` is the same as an integer.
- * This assumption is fine ABI-wise, but once you add CFI to the mix, it
- * triggers a CFI violation because `enum lru_status` gets a different CFI tag.
- *
- * This file contains a workaround until bindgen can be fixed.
- *
- * Copyright (C) 2025 Google LLC.
- */
-#include "page_range_helper.h"
-
-unsigned int rust_shrink_free_page(struct list_head *item,
- struct list_lru_one *list,
- void *cb_arg);
-
-enum lru_status
-rust_shrink_free_page_wrap(struct list_head *item, struct list_lru_one *list,
- void *cb_arg)
-{
- return rust_shrink_free_page(item, list, cb_arg);
-}
diff --git a/drivers/android/binder/page_range_helper.h b/drivers/android/binder/page_range_helper.h
deleted file mode 100644
index 18dd2dd117b2..000000000000
--- a/drivers/android/binder/page_range_helper.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2025 Google, Inc.
- */
-
-#ifndef _LINUX_PAGE_RANGE_HELPER_H
-#define _LINUX_PAGE_RANGE_HELPER_H
-
-#include <linux/list_lru.h>
-
-enum lru_status
-rust_shrink_free_page_wrap(struct list_head *item, struct list_lru_one *list,
- void *cb_arg);
-
-#endif /* _LINUX_PAGE_RANGE_HELPER_H */
diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs
index 014010662df8..632b54714e44 100644
--- a/drivers/android/binder/rust_binder_main.rs
+++ b/drivers/android/binder/rust_binder_main.rs
@@ -3,6 +3,8 @@
// Copyright (C) 2025 Google LLC.
//! Binder -- the Android IPC mechanism.
+
+#![crate_name = "rust_binder"]
#![recursion_limit = "256"]
#![allow(
clippy::as_underscore,
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index beeffe36b6cb..e833e9f537b0 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -53,18 +53,6 @@ pub(crate) struct TyrData {
pub(crate) gpu_info: GpuInfo,
}
-// Both `Clk` and `Regulator` do not implement `Send` or `Sync`, but they
-// should. There are patches on the mailing list to address this, but they have
-// not landed yet.
-//
-// For now, add this workaround so that this patch compiles with the promise
-// that it will be removed in a future patch.
-//
-// SAFETY: This will be removed in a future patch.
-unsafe impl Send for TyrData {}
-// SAFETY: This will be removed in a future patch.
-unsafe impl Sync for TyrData {}
-
fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?;
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 03a4f3599849..c1fbc54d9a41 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -293,7 +293,6 @@ impl DmaGspMem {
let (slice_1, slice_2) = {
let (slice_1, slice_2) = self.driver_write_area();
- #[allow(clippy::incompatible_msrv)]
(slice_1.as_flattened_mut(), slice_2.as_flattened_mut())
};
@@ -545,10 +544,7 @@ impl Cmdq {
Delta::from_millis(1),
timeout,
)
- .map(|(slice_1, slice_2)| {
- #[allow(clippy::incompatible_msrv)]
- (slice_1.as_flattened(), slice_2.as_flattened())
- })?;
+ .map(|(slice_1, slice_2)| (slice_1.as_flattened(), slice_2.as_flattened()))?;
// Extract the `GspMsgElement`.
let (header, slice_1) = GspMsgElement::from_bytes_prefix(slice_1).ok_or(EIO)?;
diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144.rs b/drivers/gpu/nova-core/gsp/fw/r570_144.rs
index e99d315ae74c..2e6f0d298756 100644
--- a/drivers/gpu/nova-core/gsp/fw/r570_144.rs
+++ b/drivers/gpu/nova-core/gsp/fw/r570_144.rs
@@ -7,9 +7,6 @@
//! This module may not be directly used. Please abstract or re-export the needed symbols in the
//! parent module instead.
-#![cfg_attr(test, allow(deref_nullptr))]
-#![cfg_attr(test, allow(unaligned_references))]
-#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
#![allow(
dead_code,
clippy::all,
diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
index b0e24ee724e4..6cd6fa3d2984 100644
--- a/drivers/pwm/pwm_th1520.rs
+++ b/drivers/pwm/pwm_th1520.rs
@@ -99,21 +99,6 @@ struct Th1520PwmDriverData {
clk: Clk,
}
-// This `unsafe` implementation is a temporary necessity because the underlying `kernel::clk::Clk`
-// type does not yet expose `Send` and `Sync` implementations. This block should be removed
-// as soon as the clock abstraction provides these guarantees directly.
-// TODO: Remove those unsafe impl's when Clk will support them itself.
-
-// SAFETY: The `devres` framework requires the driver's private data to be `Send` and `Sync`.
-// We can guarantee this because the PWM core synchronizes all callbacks, preventing concurrent
-// access to the contained `iomem` and `clk` resources.
-unsafe impl Send for Th1520PwmDriverData {}
-
-// SAFETY: The same reasoning applies as for `Send`. The PWM core's synchronization
-// guarantees that it is safe for multiple threads to have shared access (`&self`)
-// to the driver data during callbacks.
-unsafe impl Sync for Th1520PwmDriverData {}
-
impl pwm::PwmOps for Th1520PwmDriverData {
type WfHw = Th1520WfHw;
diff --git a/init/Kconfig b/init/Kconfig
index 7484cd703bc1..e18fa242ed86 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -82,6 +82,21 @@ config RUSTC_LLVM_VERSION
int
default $(rustc-llvm-version)
+config RUSTC_LLVM_MAJOR_VERSION
+ int
+ default $(shell,expr $(rustc-llvm-version) / 10000)
+
+config RUSTC_CLANG_LLVM_COMPATIBLE
+ bool
+ default y if CC_IS_CLANG && RUSTC_LLVM_MAJOR_VERSION = $(shell,expr $(cc-version) / 10000)
+ help
+ This indicates whether Rust and Clang use LLVM of the same major
+ version.
+
+ Operations involving handling LLVM IR or bitcode (e.g. cross-language
+ LTO) require the same LLVM major version to work properly. For best
+ compatibility it is recommended that the exact same LLVM is used.
+
config ARCH_HAS_CC_CAN_LINK
bool
@@ -163,12 +178,6 @@ config LD_CAN_USE_KEEP_IN_OVERLAY
# https://github.com/llvm/llvm-project/pull/130661
def_bool LD_IS_BFD || LLD_VERSION >= 210000
-config RUSTC_HAS_SLICE_AS_FLATTENED
- def_bool RUSTC_VERSION >= 108000
-
-config RUSTC_HAS_COERCE_POINTEE
- def_bool RUSTC_VERSION >= 108400
-
config RUSTC_HAS_SPAN_FILE
def_bool RUSTC_VERSION >= 108800
@@ -2178,9 +2187,7 @@ config RUST
depends on !DEBUG_INFO_BTF || (PAHOLE_HAS_LANG_EXCLUDE && !LTO)
depends on !CFI || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
select CFI_ICALL_NORMALIZE_INTEGERS if CFI
- depends on !CALL_PADDING || RUSTC_VERSION >= 108100
depends on !KASAN_SW_TAGS
- depends on !(MITIGATION_RETHUNK && KASAN) || RUSTC_VERSION >= 108300
help
Enables Rust support in the kernel.
@@ -2204,12 +2211,7 @@ config RUSTC_VERSION_TEXT
config BINDGEN_VERSION_TEXT
string
depends on RUST
- # The dummy parameter `workaround-for-0.69.0` is required to support 0.69.0
- # (https://github.com/rust-lang/rust-bindgen/pull/2678) and 0.71.0
- # (https://github.com/rust-lang/rust-bindgen/pull/3040). It can be removed
- # when the minimum version is upgraded past the latter (0.69.1 and 0.71.1
- # both fixed the issue).
- default "$(shell,$(BINDGEN) --version workaround-for-0.69.0 2>/dev/null)"
+ default "$(shell,$(BINDGEN) --version 2>/dev/null)"
#
# Place an empty function call at each tracepoint site. Can be
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 93f356d2b3d9..30d069676309 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -3577,6 +3577,23 @@ config RUST_KERNEL_DOCTESTS
If unsure, say N.
+config RUST_INLINE_HELPERS
+ bool "Inline C helpers into Rust code (EXPERIMENTAL)"
+ depends on RUST && RUSTC_CLANG_LLVM_COMPATIBLE
+ depends on EXPERT
+ depends on ARM64 || X86_64
+ depends on !UML
+ help
+ Inlines C helpers into Rust code using Link Time Optimization.
+
+ If this option is enabled, C helper functions declared in
+ rust/helpers/ are inlined into Rust code, which is helpful for
+ performance of Rust code. This requires a matching LLVM version for
+ Clang and rustc.
+
+ If you are sure that you're using Clang and rustc with matching LLVM
+ versions, say Y. Otherwise say N.
+
endmenu # "Rust"
endmenu # Kernel hacking
diff --git a/rust/Makefile b/rust/Makefile
index 9801af2e1e02..b361bfedfdf0 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -6,15 +6,19 @@ rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc
obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o
always-$(CONFIG_RUST) += exports_core_generated.h
+ifdef CONFIG_RUST_INLINE_HELPERS
+always-$(CONFIG_RUST) += helpers/helpers.bc helpers/helpers_module.bc
+else
+obj-$(CONFIG_RUST) += helpers/helpers.o
+always-$(CONFIG_RUST) += exports_helpers_generated.h
+endif
# Missing prototypes are expected in the helpers since these are exported
# for Rust only, thus there is no header nor prototypes.
-obj-$(CONFIG_RUST) += helpers/helpers.o
CFLAGS_REMOVE_helpers/helpers.o = -Wmissing-prototypes -Wmissing-declarations
always-$(CONFIG_RUST) += bindings/bindings_generated.rs bindings/bindings_helpers_generated.rs
obj-$(CONFIG_RUST) += bindings.o pin_init.o kernel.o
-always-$(CONFIG_RUST) += exports_helpers_generated.h \
- exports_bindings_generated.h exports_kernel_generated.h
+always-$(CONFIG_RUST) += exports_bindings_generated.h exports_kernel_generated.h
always-$(CONFIG_RUST) += uapi/uapi_generated.rs
obj-$(CONFIG_RUST) += uapi.o
@@ -71,8 +75,7 @@ core-edition := $(if $(call rustc-min-version,108700),2024,2021)
core-skip_flags := \
--edition=2021 \
- -Wunreachable_pub \
- -Wrustdoc::unescaped_backticks
+ -Wunreachable_pub
core-flags := \
--edition=$(core-edition) \
@@ -83,10 +86,8 @@ proc_macro2-cfgs := \
wrap_proc_macro \
$(if $(call rustc-min-version,108800),proc_macro_span_file proc_macro_span_location)
-# Stable since Rust 1.79.0: `feature(proc_macro_byte_character,proc_macro_c_str_literals)`.
proc_macro2-flags := \
--cap-lints=allow \
- -Zcrate-attr='feature(proc_macro_byte_character,proc_macro_c_str_literals)' \
$(call cfgs-to-flags,$(proc_macro2-cfgs))
quote-cfgs := \
@@ -118,7 +119,7 @@ syn-flags := \
$(call cfgs-to-flags,$(syn-cfgs))
pin_init_internal-cfgs := \
- kernel
+ kernel USE_RUSTC_FEATURES
pin_init_internal-flags := \
--extern proc_macro2 \
@@ -127,7 +128,7 @@ pin_init_internal-flags := \
$(call cfgs-to-flags,$(pin_init_internal-cfgs))
pin_init-cfgs := \
- kernel
+ kernel USE_RUSTC_FEATURES
pin_init-flags := \
--extern pin_init_internal \
@@ -141,15 +142,10 @@ rustdoc_modifiers_workaround := $(if $(call rustc-min-version,108800),-Cunsafe-a
# Similarly, for doctests (https://github.com/rust-lang/rust/issues/146465).
doctests_modifiers_workaround := $(rustdoc_modifiers_workaround)$(if $(call rustc-min-version,109100),$(comma)sanitizer)
-# `rustc` recognizes `--remap-path-prefix` since 1.26.0, but `rustdoc` only
-# since Rust 1.81.0. Moreover, `rustdoc` ICEs on out-of-tree builds since Rust
-# 1.82.0 (https://github.com/rust-lang/rust/issues/138520). Thus workaround both
-# issues skipping the flag. The former also applies to `RUSTDOC TK`.
quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
cmd_rustdoc = \
OBJTREE=$(abspath $(objtree)) \
- $(RUSTDOC) $(filter-out $(skip_flags) --remap-path-prefix=% --remap-path-scope=%, \
- $(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
+ $(RUSTDOC) $(filter-out $(skip_flags) --remap-path-scope=%,$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
$(rustc_target_flags) -L$(objtree)/$(obj) \
-Zunstable-options --generate-link-to-definition \
--output $(rustdoc_output) \
@@ -210,8 +206,6 @@ rustdoc-macros: $(src)/macros/lib.rs rustdoc-clean rustdoc-proc_macro2 \
rustdoc-quote rustdoc-syn FORCE
+$(call if_changed,rustdoc)
-# Starting with Rust 1.82.0, skipping `-Wrustdoc::unescaped_backticks` should
-# not be needed -- see https://github.com/rust-lang/rust/pull/128307.
rustdoc-core: private skip_flags = $(core-skip_flags)
rustdoc-core: private rustc_target_flags = $(core-flags)
rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs rustdoc-clean FORCE
@@ -335,7 +329,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
rm -rf $(objtree)/$(obj)/test/doctests/kernel; \
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
OBJTREE=$(abspath $(objtree)) \
- $(RUSTDOC) --test $(filter-out --remap-path-prefix=% --remap-path-scope=%,$(rust_flags)) \
+ $(RUSTDOC) --test $(filter-out --remap-path-scope=%,$(rust_flags)) \
-L$(objtree)/$(obj) --extern ffi --extern pin_init \
--extern kernel --extern build_error --extern macros \
--extern bindings --extern uapi \
@@ -447,22 +441,10 @@ endif
# architecture instead of generating `usize`.
bindgen_c_flags_final = $(bindgen_c_flags_lto) -fno-builtin -D__BINDGEN__
-# Each `bindgen` release may upgrade the list of Rust target versions. By
-# default, the highest stable release in their list is used. Thus we need to set
-# a `--rust-target` to avoid future `bindgen` releases emitting code that
-# `rustc` may not understand. On top of that, `bindgen` does not support passing
-# an unknown Rust target version.
-#
-# Therefore, the Rust target for `bindgen` can be only as high as the minimum
-# Rust version the kernel supports and only as high as the greatest stable Rust
-# target supported by the minimum `bindgen` version the kernel supports (that
-# is, if we do not test the actual `rustc`/`bindgen` versions running).
-#
-# Starting with `bindgen` 0.71.0, we will be able to set any future Rust version
-# instead, i.e. we will be able to set here our minimum supported Rust version.
+# `--rust-target` points to our minimum supported Rust version.
quiet_cmd_bindgen = BINDGEN $@
cmd_bindgen = \
- $(BINDGEN) $< $(bindgen_target_flags) --rust-target 1.68 \
+ $(BINDGEN) $< $(bindgen_target_flags) --rust-target 1.85 \
--use-core --with-derive-default --ctypes-prefix ffi --no-layout-tests \
--no-debug '.*' --enable-function-attribute-detection \
-o $@ -- $(bindgen_c_flags_final) -DMODULE \
@@ -496,6 +478,16 @@ $(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_extra = ;
$(obj)/bindings/bindings_helpers_generated.rs: $(src)/helpers/helpers.c FORCE
$(call if_changed_dep,bindgen)
+quiet_cmd_rust_helper = HELPER $@
+ cmd_rust_helper = \
+ $(CC) $(filter-out $(CFLAGS_REMOVE_helpers/helpers.o), $(c_flags)) \
+ -c -g0 $< -emit-llvm -o $@
+
+$(obj)/helpers/helpers.bc: private part-of-builtin := y
+$(obj)/helpers/helpers_module.bc: private part-of-module := y
+$(obj)/helpers/helpers.bc $(obj)/helpers/helpers_module.bc: $(src)/helpers/helpers.c FORCE
+ +$(call if_changed_dep,rust_helper)
+
rust_exports = $(NM) -p --defined-only $(1) | awk '$$2~/(T|R|D|B)/ && $$3!~/__(pfx|cfi|odr_asan)/ { printf $(2),$$3 }'
quiet_cmd_exports = EXPORTS $@
@@ -576,12 +568,16 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
OBJTREE=$(abspath $(objtree)) \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
$(filter-out $(skip_flags),$(rust_flags)) $(rustc_target_flags) \
- --emit=dep-info=$(depfile) --emit=obj=$@ \
+ --emit=dep-info=$(depfile) --emit=$(if $(link_helper),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) \
--emit=metadata=$(dir $@)$(patsubst %.o,lib%.rmeta,$(notdir $@)) \
--crate-type rlib -L$(objtree)/$(obj) \
--crate-name $(patsubst %.o,%,$(notdir $@)) $< \
--sysroot=/dev/null \
-Zunstable-options \
+ $(if $(link_helper),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \
+ $(obj)/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \
+ $(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \
+ $(cmd_ld_single)) \
$(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@) \
$(cmd_objtool)
@@ -591,6 +587,8 @@ rust-analyzer:
--cfgs='proc_macro2=$(proc_macro2-cfgs)' \
--cfgs='quote=$(quote-cfgs)' \
--cfgs='syn=$(syn-cfgs)' \
+ --cfgs='pin_init_internal=$(pin_init_internal-cfgs)' \
+ --cfgs='pin_init=$(pin_init-cfgs)' \
$(realpath $(srctree)) $(realpath $(objtree)) \
$(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
> rust-project.json
@@ -711,4 +709,9 @@ $(obj)/kernel.o: $(obj)/kernel/generated_arch_warn_asm.rs $(obj)/kernel/generate
endif
endif
+ifdef CONFIG_RUST_INLINE_HELPERS
+$(obj)/kernel.o: private link_helper = 1
+$(obj)/kernel.o: $(obj)/helpers/helpers.bc
+endif
+
endif # CONFIG_RUST
diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters
index fd2fd1c3cb9a..6f02d9720ad2 100644
--- a/rust/bindgen_parameters
+++ b/rust/bindgen_parameters
@@ -15,14 +15,14 @@
--opaque-type x86_msi_data
--opaque-type x86_msi_addr_lo
-# `try` is a reserved keyword since Rust 2018; solved in `bindgen` v0.59.2,
-# commit 2aed6b021680 ("context: Escape the try keyword properly").
---opaque-type kunit_try_catch
-
# If SMP is disabled, `arch_spinlock_t` is defined as a ZST which triggers a Rust
# warning. We don't need to peek into it anyway.
--opaque-type spinlock
+# enums that appear in indirect function calls should specify a cfi type
+--newtype-enum lru_status
+--with-attribute-custom-enum=lru_status='#[cfi_encoding="10lru_status"]'
+
# `seccomp`'s comment gets understood as a doctest
--no-doc-comments
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 083cc44aa952..faf3ee634ced 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -149,5 +149,4 @@ const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE;
#if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST)
#include "../../drivers/android/binder/rust_binder.h"
#include "../../drivers/android/binder/rust_binder_events.h"
-#include "../../drivers/android/binder/page_range_helper.h"
#endif
diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs
index 19f57c5b2fa2..854e7c471434 100644
--- a/rust/bindings/lib.rs
+++ b/rust/bindings/lib.rs
@@ -9,10 +9,6 @@
//! using this crate.
#![no_std]
-// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
-#![cfg_attr(test, allow(deref_nullptr))]
-#![cfg_attr(test, allow(unaligned_references))]
-#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
#![allow(
clippy::all,
missing_docs,
@@ -23,6 +19,7 @@
unreachable_pub,
unsafe_op_in_unsafe_fn
)]
+#![feature(cfi_encoding)]
#[allow(dead_code)]
#[allow(clippy::cast_lossless)]
diff --git a/rust/exports.c b/rust/exports.c
index 587f0e776aba..1b52460b0f4e 100644
--- a/rust/exports.c
+++ b/rust/exports.c
@@ -16,10 +16,13 @@
#define EXPORT_SYMBOL_RUST_GPL(sym) extern int sym; EXPORT_SYMBOL_GPL(sym)
#include "exports_core_generated.h"
-#include "exports_helpers_generated.h"
#include "exports_bindings_generated.h"
#include "exports_kernel_generated.h"
+#ifndef CONFIG_RUST_INLINE_HELPERS
+#include "exports_helpers_generated.h"
+#endif
+
// For modules using `rust/build_error.rs`.
#ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW
EXPORT_SYMBOL_RUST_GPL(rust_build_error);
diff --git a/rust/helpers/clk.c b/rust/helpers/clk.c
index 6d04372c9f3b..15fd7e469cdd 100644
--- a/rust/helpers/clk.c
+++ b/rust/helpers/clk.c
@@ -7,60 +7,62 @@
* CONFIG_HAVE_CLK or CONFIG_HAVE_CLK_PREPARE aren't set.
*/
#ifndef CONFIG_HAVE_CLK
-struct clk *rust_helper_clk_get(struct device *dev, const char *id)
+__rust_helper struct clk *rust_helper_clk_get(struct device *dev,
+ const char *id)
{
return clk_get(dev, id);
}
-void rust_helper_clk_put(struct clk *clk)
+__rust_helper void rust_helper_clk_put(struct clk *clk)
{
clk_put(clk);
}
-int rust_helper_clk_enable(struct clk *clk)
+__rust_helper int rust_helper_clk_enable(struct clk *clk)
{
return clk_enable(clk);
}
-void rust_helper_clk_disable(struct clk *clk)
+__rust_helper void rust_helper_clk_disable(struct clk *clk)
{
clk_disable(clk);
}
-unsigned long rust_helper_clk_get_rate(struct clk *clk)
+__rust_helper unsigned long rust_helper_clk_get_rate(struct clk *clk)
{
return clk_get_rate(clk);
}
-int rust_helper_clk_set_rate(struct clk *clk, unsigned long rate)
+__rust_helper int rust_helper_clk_set_rate(struct clk *clk, unsigned long rate)
{
return clk_set_rate(clk, rate);
}
#endif
#ifndef CONFIG_HAVE_CLK_PREPARE
-int rust_helper_clk_prepare(struct clk *clk)
+__rust_helper int rust_helper_clk_prepare(struct clk *clk)
{
return clk_prepare(clk);
}
-void rust_helper_clk_unprepare(struct clk *clk)
+__rust_helper void rust_helper_clk_unprepare(struct clk *clk)
{
clk_unprepare(clk);
}
#endif
-struct clk *rust_helper_clk_get_optional(struct device *dev, const char *id)
+__rust_helper struct clk *rust_helper_clk_get_optional(struct device *dev,
+ const char *id)
{
return clk_get_optional(dev, id);
}
-int rust_helper_clk_prepare_enable(struct clk *clk)
+__rust_helper int rust_helper_clk_prepare_enable(struct clk *clk)
{
return clk_prepare_enable(clk);
}
-void rust_helper_clk_disable_unprepare(struct clk *clk)
+__rust_helper void rust_helper_clk_disable_unprepare(struct clk *clk)
{
clk_disable_unprepare(clk);
}
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index a3c42e51f00a..e05c6e7e4abb 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -7,7 +7,36 @@
* Sorted alphabetically.
*/
+#include <linux/compiler_types.h>
+
+#ifdef __BINDGEN__
+// Omit `inline` for bindgen as it ignores inline functions.
#define __rust_helper
+#else
+// The helper functions are all inline functions.
+//
+// We use `__always_inline` here to bypass LLVM inlining checks, in case the
+// helpers are inlined directly into Rust CGUs.
+//
+// The LLVM inlining checks are false positives:
+// * LLVM doesn't want to inline functions compiled with
+// `-fno-delete-null-pointer-checks` with code compiled without.
+// The C CGUs all have this enabled and Rust CGUs don't. Inlining is okay
+// since this is one of the hardening features that does not change the ABI,
+// and we shouldn't have null pointer dereferences in these helpers.
+// * LLVM doesn't want to inline functions with different list of builtins. C
+// side has `-fno-builtin-wcslen`; `wcslen` is not a Rust builtin, so they
+// should be compatible, but LLVM does not perform inlining due to attributes
+// mismatch.
+// * clang and Rust doesn't have the exact target string. Clang generates
+// `+cmov,+cx8,+fxsr` but Rust doesn't enable them (in fact, Rust will
+// complain if `-Ctarget-feature=+cmov,+cx8,+fxsr` is used). x86-64 always
+// enable these features, so they are in fact the same target string, but
+// LLVM doesn't understand this and so inlining is inhibited. This can be
+// bypassed with `--ignore-tti-inline-compatible`, but this is a hidden
+// option.
+#define __rust_helper __always_inline
+#endif
#include "atomic.c"
#include "atomic_ext.c"
diff --git a/rust/helpers/jump_label.c b/rust/helpers/jump_label.c
index fc1f1e0df08e..7ca384e73121 100644
--- a/rust/helpers/jump_label.c
+++ b/rust/helpers/jump_label.c
@@ -7,7 +7,7 @@
#include <linux/jump_label.h>
#ifndef CONFIG_JUMP_LABEL
-int rust_helper_static_key_count(struct static_key *key)
+__rust_helper int rust_helper_static_key_count(struct static_key *key)
{
return static_key_count(key);
}
diff --git a/rust/kernel/alloc/allocator/iter.rs b/rust/kernel/alloc/allocator/iter.rs
index 5759f86029b7..e0a70b7a744a 100644
--- a/rust/kernel/alloc/allocator/iter.rs
+++ b/rust/kernel/alloc/allocator/iter.rs
@@ -42,15 +42,9 @@ impl<'a> Iterator for VmallocPageIter<'a> {
return None;
}
- // TODO: Use `NonNull::add()` instead, once the minimum supported compiler version is
- // bumped to 1.80 or later.
- //
// SAFETY: `offset` is in the interval `[0, (self.page_count() - 1) * page::PAGE_SIZE]`,
// hence the resulting pointer is guaranteed to be within the same allocation.
- let ptr = unsafe { self.buf.as_ptr().add(offset) };
-
- // SAFETY: `ptr` is guaranteed to be non-null given that it is derived from `self.buf`.
- let ptr = unsafe { NonNull::new_unchecked(ptr) };
+ let ptr = unsafe { self.buf.add(offset) };
// SAFETY:
// - `ptr` is a valid pointer to a `Vmalloc` allocation.
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index 622b3529edfc..bd6da02c7ab8 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -77,33 +77,8 @@ use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption};
/// `self.0` is always properly aligned and either points to memory allocated with `A` or, for
/// zero-sized types, is a dangling, well aligned pointer.
#[repr(transparent)]
-#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
-pub struct Box<#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, pointee)] T: ?Sized, A: Allocator>(
- NonNull<T>,
- PhantomData<A>,
-);
-
-// This is to allow coercion from `Box<T, A>` to `Box<U, A>` if `T` can be converted to the
-// dynamically-sized type (DST) `U`.
-#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
-impl<T, U, A> core::ops::CoerceUnsized<Box<U, A>> for Box<T, A>
-where
- T: ?Sized + core::marker::Unsize<U>,
- U: ?Sized,
- A: Allocator,
-{
-}
-
-// This is to allow `Box<U, A>` to be dispatched on when `Box<T, A>` can be coerced into `Box<U,
-// A>`.
-#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
-impl<T, U, A> core::ops::DispatchFromDyn<Box<U, A>> for Box<T, A>
-where
- T: ?Sized + core::marker::Unsize<U>,
- U: ?Sized,
- A: Allocator,
-{
-}
+#[derive(core::marker::CoercePointee)]
+pub struct Box<#[pointee] T: ?Sized, A: Allocator>(NonNull<T>, PhantomData<A>);
/// Type alias for [`Box`] with a [`Kmalloc`] allocator.
///
diff --git a/rust/kernel/alloc/kvec/errors.rs b/rust/kernel/alloc/kvec/errors.rs
index e7de5049ee47..985c5f2c3962 100644
--- a/rust/kernel/alloc/kvec/errors.rs
+++ b/rust/kernel/alloc/kvec/errors.rs
@@ -15,6 +15,7 @@ impl<T> fmt::Debug for PushError<T> {
}
impl<T> From<PushError<T>> for Error {
+ #[inline]
fn from(_: PushError<T>) -> Error {
// Returning ENOMEM isn't appropriate because the system is not out of memory. The vector
// is just full and we are refusing to resize it.
@@ -32,6 +33,7 @@ impl fmt::Debug for RemoveError {
}
impl From<RemoveError> for Error {
+ #[inline]
fn from(_: RemoveError) -> Error {
EINVAL
}
@@ -55,6 +57,7 @@ impl<T> fmt::Debug for InsertError<T> {
}
impl<T> From<InsertError<T>> for Error {
+ #[inline]
fn from(_: InsertError<T>) -> Error {
EINVAL
}
diff --git a/rust/kernel/block/mq/gen_disk.rs b/rust/kernel/block/mq/gen_disk.rs
index c8b0ecb17082..912cb805caf5 100644
--- a/rust/kernel/block/mq/gen_disk.rs
+++ b/rust/kernel/block/mq/gen_disk.rs
@@ -140,9 +140,7 @@ impl GenDiskBuilder {
devnode: None,
alternative_gpt_sector: None,
get_unique_id: None,
- // TODO: Set to THIS_MODULE. Waiting for const_refs_to_static feature to
- // be merged (unstable in rustc 1.78 which is staged for linux 6.10)
- // <https://github.com/rust-lang/rust/issues/119618>
+ // TODO: Set to `THIS_MODULE`.
owner: core::ptr::null_mut(),
pr_ops: core::ptr::null_mut(),
free_disk: None,
diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
index f8124dbc663f..2ea2154ec30c 100644
--- a/rust/kernel/build_assert.rs
+++ b/rust/kernel/build_assert.rs
@@ -1,10 +1,144 @@
// SPDX-License-Identifier: GPL-2.0
-//! Build-time assert.
+//! Various assertions that happen during build-time.
+//!
+//! There are three types of build-time assertions that you can use:
+//! - [`static_assert!`]
+//! - [`const_assert!`]
+//! - [`build_assert!`]
+//!
+//! The ones towards the bottom of the list are more expressive, while the ones towards the top of
+//! the list are more robust and trigger earlier in the compilation pipeline. Therefore, you should
+//! prefer the ones towards the top of the list wherever possible.
+//!
+//! # Choosing the correct assertion
+//!
+//! If you're asserting outside any bodies (e.g. initializers or function bodies), you should use
+//! [`static_assert!`] as it is the only assertion that can be used in that context.
+//!
+//! Inside bodies, if your assertion condition does not depend on any variable or generics, you
+//! should use [`static_assert!`]. If the condition depends on generics, but not variables
+//! (including function arguments), you should use [`const_assert!`]. Otherwise, use
+//! [`build_assert!`]. The same is true regardless if the function is `const fn`.
+//!
+//! ```
+//! // Outside any bodies.
+//! static_assert!(core::mem::size_of::<u8>() == 1);
+//! // `const_assert!` and `build_assert!` cannot be used here, they will fail to compile.
+//!
+//! #[inline(always)]
+//! fn foo<const N: usize>(v: usize) {
+//! static_assert!(core::mem::size_of::<u8>() == 1); // Preferred.
+//! const_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
+//! build_assert!(core::mem::size_of::<u8>() == 1); // Discouraged.
+//!
+//! // `static_assert!(N > 1);` is not allowed.
+//! const_assert!(N > 1); // Preferred.
+//! build_assert!(N > 1); // Discouraged.
+//!
+//! // `static_assert!(v > 1);` is not allowed.
+//! // `const_assert!(v > 1);` is not allowed.
+//! build_assert!(v > 1); // Works.
+//! }
+//! ```
+//!
+//! # Detailed behavior
+//!
+//! `static_assert!()` is equivalent to `static_assert` in C. It requires `expr` to be a constant
+//! expression. This expression cannot refer to any generics. A `static_assert!(expr)` in a program
+//! is always evaluated, regardless if the function it appears in is used or not. This is also the
+//! only usable assertion outside a body.
+//!
+//! `const_assert!()` has no direct C equivalence. It is a more powerful version of
+//! `static_assert!()`, where it may refer to generics in a function. Note that due to the ability
+//! to refer to generics, the assertion is tied to a specific instance of a function. So if it is
+//! used in a generic function that is not instantiated, the assertion will not be checked. For this
+//! reason, `static_assert!()` is preferred wherever possible.
+//!
+//! `build_assert!()` is equivalent to `BUILD_BUG_ON`. It is even more powerful than
+//! `const_assert!()` because it can be used to check tautologies that depend on runtime value (this
+//! is the same as `BUILD_BUG_ON`). However, the assertion failure mechanism can possibly be
+//! undefined symbols and linker errors, it is not developer friendly to debug, so it is recommended
+//! to avoid it and prefer other two assertions where possible.
+
+pub use crate::{
+ build_assert,
+ build_error,
+ const_assert,
+ static_assert, //
+};
#[doc(hidden)]
pub use build_error::build_error;
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// An optional panic message can be supplied after the expression.
+/// Currently only a string literal without formatting is supported
+/// due to constness limitations of the [`assert!`] macro.
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// You cannot refer to generics or variables with [`static_assert!`]. If you need to refer to
+/// generics, use [`const_assert!`]; if you need to refer to variables, use [`build_assert!`]. See
+/// the [module documentation](self).
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == b'a');
+///
+/// const fn f(x: i32) -> i32 {
+/// x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input.");
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+ ($condition:expr $(,$arg:literal)?) => {
+ const _: () = ::core::assert!($condition $(,$arg)?);
+ };
+}
+
+/// Assertion during constant evaluation.
+///
+/// This is a more powerful version of [`static_assert!`] that can refer to generics inside
+/// functions or implementation blocks. However, it also has a limitation where it can only appear
+/// in places where statements can appear; for example, you cannot use it as an item in the module.
+///
+/// [`static_assert!`] should be preferred if no generics are referred to in the condition. You
+/// cannot refer to variables with [`const_assert!`] (even inside `const fn`); if you need the
+/// capability, use [`build_assert!`]. See the [module documentation](self).
+///
+/// # Examples
+///
+/// ```
+/// fn foo<const N: usize>() {
+/// const_assert!(N > 1);
+/// }
+///
+/// fn bar<T>() {
+/// const_assert!(size_of::<T>() > 0, "T cannot be ZST");
+/// }
+/// ```
+#[macro_export]
+macro_rules! const_assert {
+ ($condition:expr $(,$arg:literal)?) => {
+ const { ::core::assert!($condition $(,$arg)?) };
+ };
+}
+
/// Fails the build if the code path calling `build_error!` can possibly be executed.
///
/// If the macro is executed in const context, `build_error!` will panic.
@@ -38,44 +172,33 @@ macro_rules! build_error {
/// will panic. If the compiler or optimizer cannot guarantee the condition will
/// be evaluated to `true`, a build error will be triggered.
///
-/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+/// When a condition depends on a function argument, the function must be annotated with
+/// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the
+/// function, preventing it from optimizing out the error path.
+///
+/// If the assertion condition does not depend on any variables or generics, you should use
+/// [`static_assert!`]. If the assertion condition does not depend on variables, but does depend on
+/// generics, you should use [`const_assert!`]. See the [module documentation](self).
///
/// # Examples
///
-/// These examples show that different types of [`assert!`] will trigger errors
-/// at different stage of compilation. It is preferred to err as early as
-/// possible, so [`static_assert!`] should be used whenever possible.
-/// ```ignore
-/// fn foo() {
-/// static_assert!(1 > 1); // Compile-time error
-/// build_assert!(1 > 1); // Build-time error
-/// assert!(1 > 1); // Run-time error
-/// }
/// ```
+/// #[inline(always)] // Important.
+/// fn bar(n: usize) {
+/// build_assert!(n > 1);
+/// }
///
-/// When the condition refers to generic parameters or parameters of an inline function,
-/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
-/// ```
-/// fn foo<const N: usize>() {
-/// // `static_assert!(N > 1);` is not allowed
-/// build_assert!(N > 1); // Build-time check
-/// assert!(N > 1); // Run-time check
+/// fn foo() {
+/// bar(2);
/// }
-/// ```
///
-/// When a condition depends on a function argument, the function must be annotated with
-/// `#[inline(always)]`. Without this attribute, the compiler may choose to not inline the
-/// function, preventing it from optimizing out the error path.
-/// ```
-/// #[inline(always)]
-/// fn bar(n: usize) {
-/// // `static_assert!(n > 1);` is not allowed
-/// build_assert!(n > 1); // Build-time check
-/// assert!(n > 1); // Run-time check
+/// #[inline(always)] // Important.
+/// const fn const_bar(n: usize) {
+/// build_assert!(n > 1);
/// }
-/// ```
///
-/// [`static_assert!`]: crate::static_assert!
+/// const _: () = const_bar(2);
+/// ```
#[macro_export]
macro_rules! build_assert {
($cond:expr $(,)?) => {{
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index 4059aff34d09..7abbd0767d8c 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -128,6 +128,13 @@ mod common_clk {
#[repr(transparent)]
pub struct Clk(*mut bindings::clk);
+ // SAFETY: It is safe to call `clk_put` on another thread than where `clk_get` was called.
+ unsafe impl Send for Clk {}
+
+ // SAFETY: It is safe to call any combination of the `&self` methods in parallel, as the
+ // methods are synchronized internally.
+ unsafe impl Sync for Clk {}
+
impl Clk {
/// Gets [`Clk`] corresponding to a [`Device`] and a connection id.
///
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 258b12afdcba..decceb6ae855 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -216,36 +216,42 @@ impl fmt::Debug for Error {
}
impl From<AllocError> for Error {
+ #[inline]
fn from(_: AllocError) -> Error {
code::ENOMEM
}
}
impl From<TryFromIntError> for Error {
+ #[inline]
fn from(_: TryFromIntError) -> Error {
code::EINVAL
}
}
impl From<Utf8Error> for Error {
+ #[inline]
fn from(_: Utf8Error) -> Error {
code::EINVAL
}
}
impl From<LayoutError> for Error {
+ #[inline]
fn from(_: LayoutError) -> Error {
code::ENOMEM
}
}
impl From<fmt::Error> for Error {
+ #[inline]
fn from(_: fmt::Error) -> Error {
code::EINVAL
}
}
impl From<core::convert::Infallible> for Error {
+ #[inline]
fn from(e: core::convert::Infallible) -> Error {
match e {}
}
@@ -446,6 +452,9 @@ pub fn to_result(err: crate::ffi::c_int) -> Result {
/// for errors. This function performs the check and converts the "error pointer"
/// to a normal pointer in an idiomatic fashion.
///
+/// Note that a `NULL` pointer is not considered an error pointer, and is returned
+/// as-is, wrapped in [`Ok`].
+///
/// # Examples
///
/// ```ignore
@@ -460,6 +469,34 @@ pub fn to_result(err: crate::ffi::c_int) -> Result {
/// from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) })
/// }
/// ```
+///
+/// ```
+/// # use kernel::error::from_err_ptr;
+/// # mod bindings {
+/// # #![expect(clippy::missing_safety_doc)]
+/// # use kernel::prelude::*;
+/// # pub(super) unsafe fn einval_err_ptr() -> *mut kernel::ffi::c_void {
+/// # EINVAL.to_ptr()
+/// # }
+/// # pub(super) unsafe fn null_ptr() -> *mut kernel::ffi::c_void {
+/// # core::ptr::null_mut()
+/// # }
+/// # pub(super) unsafe fn non_null_ptr() -> *mut kernel::ffi::c_void {
+/// # 0x1234 as *mut kernel::ffi::c_void
+/// # }
+/// # }
+/// // SAFETY: ...
+/// let einval_err = from_err_ptr(unsafe { bindings::einval_err_ptr() });
+/// assert_eq!(einval_err, Err(EINVAL));
+///
+/// // SAFETY: ...
+/// let null_ok = from_err_ptr(unsafe { bindings::null_ptr() });
+/// assert_eq!(null_ok, Ok(core::ptr::null_mut()));
+///
+/// // SAFETY: ...
+/// let non_null = from_err_ptr(unsafe { bindings::non_null_ptr() }).unwrap();
+/// assert_ne!(non_null, core::ptr::null_mut());
+/// ```
pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
// CAST: Casting a pointer to `*const crate::ffi::c_void` is always valid.
let const_ptr: *const crate::ffi::c_void = ptr.cast();
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index bb5b830f48c3..7b908f0c5a58 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -16,10 +16,11 @@ use crate::{
error::*,
of,
prelude::*,
- types::{
- AlwaysRefCounted,
- Opaque, //
- }, //
+ sync::aref::{
+ ARef,
+ AlwaysRefCounted, //
+ },
+ types::Opaque, //
};
use core::{
@@ -31,8 +32,6 @@ use core::{
}, //
};
-use kernel::types::ARef;
-
/// An I2C device id table.
#[repr(transparent)]
#[derive(Clone, Copy)]
@@ -416,7 +415,7 @@ kernel::impl_device_context_deref!(unsafe { I2cAdapter });
kernel::impl_device_context_into_aref!(I2cAdapter);
// SAFETY: Instances of `I2cAdapter` are always reference-counted.
-unsafe impl crate::types::AlwaysRefCounted for I2cAdapter {
+unsafe impl AlwaysRefCounted for I2cAdapter {
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
unsafe { bindings::i2c_get_adapter(self.index()) };
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index d93292d47420..0fa9d820fe7c 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -16,45 +16,14 @@
// Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
// the unstable features in use.
//
-// Stable since Rust 1.79.0.
-#![feature(generic_nonzero)]
-#![feature(inline_const)]
-#![feature(pointer_is_aligned)]
-#![feature(slice_ptr_len)]
-//
-// Stable since Rust 1.80.0.
-#![feature(slice_flatten)]
-//
-// Stable since Rust 1.81.0.
-#![feature(lint_reasons)]
-//
-// Stable since Rust 1.82.0.
-#![feature(raw_ref_op)]
-//
-// Stable since Rust 1.83.0.
-#![feature(const_maybe_uninit_as_mut_ptr)]
-#![feature(const_mut_refs)]
-#![feature(const_option)]
-#![feature(const_ptr_write)]
-#![feature(const_refs_to_cell)]
-//
-// Stable since Rust 1.84.0.
-#![feature(strict_provenance)]
-//
// Expected to become stable.
#![feature(arbitrary_self_types)]
+#![feature(derive_coerce_pointee)]
//
// To be determined.
#![feature(used_with_arg)]
//
-// `feature(derive_coerce_pointee)` is expected to become stable. Before Rust
-// 1.84.0, it did not exist, so enable the predecessor features.
-#![cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, feature(derive_coerce_pointee))]
-#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(coerce_unsized))]
-#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(dispatch_from_dyn))]
-#![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(unsize))]
-//
-// `feature(file_with_nul)` is expected to become stable. Before Rust 1.89.0, it did not exist, so
+// `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))]
@@ -77,7 +46,6 @@ pub mod bits;
#[cfg(CONFIG_BLOCK)]
pub mod block;
pub mod bug;
-#[doc(hidden)]
pub mod build_assert;
pub mod clk;
#[cfg(CONFIG_CONFIGFS_FS)]
@@ -145,10 +113,8 @@ pub mod scatterlist;
pub mod security;
pub mod seq_file;
pub mod sizes;
-pub mod slice;
#[cfg(CONFIG_SOC_BUS)]
pub mod soc;
-mod static_assert;
#[doc(hidden)]
pub mod std_vendor;
pub mod str;
diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs
index 8349ff32fc37..406e3a028c55 100644
--- a/rust/kernel/list.rs
+++ b/rust/kernel/list.rs
@@ -12,15 +12,31 @@ use core::ptr;
use pin_init::PinInit;
mod impl_list_item_mod;
+#[doc(inline)]
pub use self::impl_list_item_mod::{
- impl_has_list_links, impl_has_list_links_self_ptr, impl_list_item, HasListLinks, HasSelfPtr,
+ impl_has_list_links,
+ impl_has_list_links_self_ptr,
+ impl_list_item,
+ HasListLinks,
+ HasSelfPtr, //
};
mod arc;
-pub use self::arc::{impl_list_arc_safe, AtomicTracker, ListArc, ListArcSafe, TryNewListArc};
+#[doc(inline)]
+pub use self::arc::{
+ impl_list_arc_safe,
+ AtomicTracker,
+ ListArc,
+ ListArcSafe,
+ TryNewListArc, //
+};
mod arc_field;
-pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
+#[doc(inline)]
+pub use self::arc_field::{
+ define_list_arc_field_getter,
+ ListArcField, //
+};
/// A linked list.
///
diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs
index 2282f33913ee..a9a2b0178f65 100644
--- a/rust/kernel/list/arc.rs
+++ b/rust/kernel/list/arc.rs
@@ -82,6 +82,7 @@ pub unsafe trait TryNewListArc<const ID: u64 = 0>: ListArcSafe<ID> {
/// [`AtomicTracker`]. However, it is also possible to defer the tracking to another struct
/// using also using this macro.
#[macro_export]
+#[doc(hidden)]
macro_rules! impl_list_arc_safe {
(impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked; } $($rest:tt)*) => {
impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t {
@@ -159,7 +160,7 @@ pub use impl_list_arc_safe;
///
/// [`List`]: crate::list::List
#[repr(transparent)]
-#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
+#[derive(core::marker::CoercePointee)]
pub struct ListArc<T, const ID: u64 = 0>
where
T: ListArcSafe<ID> + ?Sized,
@@ -442,26 +443,6 @@ where
}
}
-// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the
-// dynamically-sized type (DST) `U`.
-#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
-impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID>
-where
- T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
- U: ListArcSafe<ID> + ?Sized,
-{
-}
-
-// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
-// `ListArc<U>`.
-#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
-impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
-where
- T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
- U: ListArcSafe<ID> + ?Sized,
-{
-}
-
/// A utility for tracking whether a [`ListArc`] exists using an atomic.
///
/// # Invariants
diff --git a/rust/kernel/list/arc_field.rs b/rust/kernel/list/arc_field.rs
index c4b9dd503982..2ad8aea55993 100644
--- a/rust/kernel/list/arc_field.rs
+++ b/rust/kernel/list/arc_field.rs
@@ -66,6 +66,7 @@ impl<T, const ID: u64> ListArcField<T, ID> {
/// Defines getters for a [`ListArcField`].
#[macro_export]
+#[doc(hidden)]
macro_rules! define_list_arc_field_getter {
($pub:vis fn $name:ident(&self $(<$id:tt>)?) -> &$typ:ty { $field:ident }
$($rest:tt)*
diff --git a/rust/kernel/list/impl_list_item_mod.rs b/rust/kernel/list/impl_list_item_mod.rs
index ee53d0387e63..5a3eac9f3cf0 100644
--- a/rust/kernel/list/impl_list_item_mod.rs
+++ b/rust/kernel/list/impl_list_item_mod.rs
@@ -29,6 +29,7 @@ pub unsafe trait HasListLinks<const ID: u64 = 0> {
/// Implements the [`HasListLinks`] trait for the given type.
#[macro_export]
+#[doc(hidden)]
macro_rules! impl_has_list_links {
($(impl$({$($generics:tt)*})?
HasListLinks$(<$id:tt>)?
@@ -74,6 +75,7 @@ where
/// Implements the [`HasListLinks`] and [`HasSelfPtr`] traits for the given type.
#[macro_export]
+#[doc(hidden)]
macro_rules! impl_has_list_links_self_ptr {
($(impl$({$($generics:tt)*})?
HasSelfPtr<$item_type:ty $(, $id:tt)?>
@@ -181,6 +183,7 @@ pub use impl_has_list_links_self_ptr;
/// }
/// ```
#[macro_export]
+#[doc(hidden)]
macro_rules! impl_list_item {
(
$(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty {
diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
index fa81acbdc8c2..54d0ce3ba595 100644
--- a/rust/kernel/num/bounded.rs
+++ b/rust/kernel/num/bounded.rs
@@ -255,9 +255,7 @@ macro_rules! impl_const_new {
/// ```
pub const fn new<const VALUE: $type>() -> Self {
// Statically assert that `VALUE` fits within the set number of bits.
- const {
- assert!(fits_within!(VALUE, $type, N));
- }
+ const_assert!(fits_within!(VALUE, $type, N));
// SAFETY: `fits_within` confirmed that `VALUE` can be represented within
// `N` bits.
@@ -287,12 +285,10 @@ where
/// The caller must ensure that `value` can be represented within `N` bits.
const unsafe fn __new(value: T) -> Self {
// Enforce the type invariants.
- const {
- // `N` cannot be zero.
- assert!(N != 0);
- // The backing type is at least as large as `N` bits.
- assert!(N <= T::BITS);
- }
+ // `N` cannot be zero.
+ const_assert!(N != 0);
+ // The backing type is at least as large as `N` bits.
+ const_assert!(N <= T::BITS);
// INVARIANT: The caller ensures `value` fits within `N` bits.
Self(value)
@@ -406,12 +402,10 @@ where
/// assert_eq!(larger_v, v);
/// ```
pub const fn extend<const M: u32>(self) -> Bounded<T, M> {
- const {
- assert!(
- M >= N,
- "Requested number of bits is less than the current representation."
- );
- }
+ const_assert!(
+ M >= N,
+ "Requested number of bits is less than the current representation."
+ );
// SAFETY: The value did fit within `N` bits, so it will all the more fit within
// the larger `M` bits.
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 2877e3f7b6d3..44edf72a4a24 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -13,43 +13,97 @@
#[doc(no_inline)]
pub use core::{
- mem::{align_of, align_of_val, size_of, size_of_val},
- pin::Pin,
+ mem::{
+ align_of,
+ align_of_val,
+ size_of,
+ size_of_val, //
+ },
+ pin::Pin, //
};
pub use ::ffi::{
- c_char, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong,
- c_ushort, c_void, CStr,
+ c_char,
+ c_int,
+ c_long,
+ c_longlong,
+ c_schar,
+ c_short,
+ c_uchar,
+ c_uint,
+ c_ulong,
+ c_ulonglong,
+ c_ushort,
+ c_void,
+ CStr, //
};
-pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec};
-
#[doc(no_inline)]
-pub use macros::{export, fmt, kunit_tests, module, vtable};
+pub use macros::{
+ export,
+ fmt,
+ kunit_tests,
+ module,
+ vtable, //
+};
-pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable};
+pub use pin_init::{
+ init,
+ pin_data,
+ pin_init,
+ pinned_drop,
+ InPlaceWrite,
+ Init,
+ PinInit,
+ Zeroable, //
+};
-pub use super::{build_assert, build_error};
+pub use super::{
+ alloc::{
+ flags::*,
+ Box,
+ KBox,
+ KVBox,
+ KVVec,
+ KVec,
+ VBox,
+ VVec,
+ Vec, //
+ },
+ build_assert,
+ build_error,
+ const_assert,
+ current,
+ dev_alert,
+ dev_crit,
+ dev_dbg,
+ dev_emerg,
+ dev_err,
+ dev_info,
+ dev_notice,
+ dev_warn,
+ error::{
+ code::*,
+ Error,
+ Result, //
+ },
+ init::InPlaceInit,
+ pr_alert,
+ pr_crit,
+ pr_debug,
+ pr_emerg,
+ pr_err,
+ pr_info,
+ pr_notice,
+ pr_warn,
+ static_assert,
+ str::CStrExt as _,
+ try_init,
+ try_pin_init,
+ uaccess::UserPtr,
+ ThisModule, //
+};
// `super::std_vendor` is hidden, which makes the macro inline for some reason.
#[doc(no_inline)]
pub use super::dbg;
-pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn};
-pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
-
-pub use super::{try_init, try_pin_init};
-
-pub use super::static_assert;
-
-pub use super::error::{code::*, Error, Result};
-
-pub use super::{str::CStrExt as _, ThisModule};
-
-pub use super::init::InPlaceInit;
-
-pub use super::current;
-
-pub use super::uaccess::UserPtr;
-
-#[cfg(not(CONFIG_RUSTC_HAS_SLICE_AS_FLATTENED))]
-pub use super::slice::AsFlattened;
diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
index bdc2d79ff669..3f3e529e9f58 100644
--- a/rust/kernel/ptr.rs
+++ b/rust/kernel/ptr.rs
@@ -11,6 +11,8 @@ use core::mem::{
};
use core::num::NonZero;
+use crate::const_assert;
+
/// Type representing an alignment, which is always a power of two.
///
/// It is used to validate that a given value is a valid alignment, and to perform masking and
@@ -44,12 +46,10 @@ impl Alignment {
/// ```
#[inline(always)]
pub const fn new<const ALIGN: usize>() -> Self {
- const {
- assert!(
- ALIGN.is_power_of_two(),
- "Provided alignment is not a power of two."
- );
- }
+ const_assert!(
+ ALIGN.is_power_of_two(),
+ "Provided alignment is not a power of two."
+ );
// INVARIANT: `align` is a power of two.
// SAFETY: `align` is a power of two, and thus non-zero.
@@ -87,7 +87,6 @@ impl Alignment {
/// This is equivalent to [`align_of`], but with the return value provided as an [`Alignment`].
#[inline(always)]
pub const fn of<T>() -> Self {
- #![allow(clippy::incompatible_msrv)]
// This cannot panic since alignments are always powers of two.
//
// We unfortunately cannot use `new` as it would require the `generic_const_exprs` feature.
@@ -253,3 +252,32 @@ impl<T> KnownSize for [T] {
p.len() * size_of::<T>()
}
}
+
+/// Aligns `value` up to `align`.
+///
+/// This is the const-compatible equivalent of [`Alignable::align_up`].
+///
+/// Returns [`None`] on overflow.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::{
+/// ptr::{
+/// const_align_up,
+/// Alignment, //
+/// },
+/// sizes::SZ_4K, //
+/// };
+///
+/// assert_eq!(const_align_up(0x4f, Alignment::new::<16>()), Some(0x50));
+/// assert_eq!(const_align_up(0x40, Alignment::new::<16>()), Some(0x40));
+/// assert_eq!(const_align_up(1, Alignment::new::<SZ_4K>()), Some(SZ_4K));
+/// ```
+#[inline(always)]
+pub const fn const_align_up(value: usize, align: Alignment) -> Option<usize> {
+ match value.checked_add(align.as_usize() - 1) {
+ Some(v) => Some(v & align.mask()),
+ None => None,
+ }
+}
diff --git a/rust/kernel/sizes.rs b/rust/kernel/sizes.rs
index 661e680d9330..521b2b38bfe7 100644
--- a/rust/kernel/sizes.rs
+++ b/rust/kernel/sizes.rs
@@ -3,48 +3,132 @@
//! Commonly used sizes.
//!
//! C headers: [`include/linux/sizes.h`](srctree/include/linux/sizes.h).
+//!
+//! The top-level `SZ_*` constants are [`usize`]-typed, for use in kernel page
+//! arithmetic and similar CPU-side work.
+//!
+//! The [`SizeConstants`] trait provides the same constants as associated constants
+//! on [`u32`], [`u64`], and [`usize`], for use in device address spaces where
+//! the address width depends on the hardware. Device drivers frequently need
+//! these constants as [`u64`] (or [`u32`]) rather than [`usize`], because
+//! device address spaces are sized independently of the CPU pointer width.
+//!
+//! # Examples
+//!
+//! ```
+//! use kernel::{
+//! page::PAGE_SIZE,
+//! sizes::{
+//! SizeConstants,
+//! SZ_1M, //
+//! }, //
+//! };
+//!
+//! // Module-level constants continue to work without a type qualifier.
+//! let num_pages_in_1m = SZ_1M / PAGE_SIZE;
+//!
+//! // Trait associated constants require a type qualifier.
+//! let heap_size = 14 * u64::SZ_1M;
+//! let small = u32::SZ_4K;
+//! ```
+
+macro_rules! define_sizes {
+ ($($type:ty),* $(,)?) => {
+ define_sizes!(@internal [$($type),*]
+ /// `0x0000_0400`.
+ SZ_1K,
+ /// `0x0000_0800`.
+ SZ_2K,
+ /// `0x0000_1000`.
+ SZ_4K,
+ /// `0x0000_2000`.
+ SZ_8K,
+ /// `0x0000_4000`.
+ SZ_16K,
+ /// `0x0000_8000`.
+ SZ_32K,
+ /// `0x0001_0000`.
+ SZ_64K,
+ /// `0x0002_0000`.
+ SZ_128K,
+ /// `0x0004_0000`.
+ SZ_256K,
+ /// `0x0008_0000`.
+ SZ_512K,
+ /// `0x0010_0000`.
+ SZ_1M,
+ /// `0x0020_0000`.
+ SZ_2M,
+ /// `0x0040_0000`.
+ SZ_4M,
+ /// `0x0080_0000`.
+ SZ_8M,
+ /// `0x0100_0000`.
+ SZ_16M,
+ /// `0x0200_0000`.
+ SZ_32M,
+ /// `0x0400_0000`.
+ SZ_64M,
+ /// `0x0800_0000`.
+ SZ_128M,
+ /// `0x1000_0000`.
+ SZ_256M,
+ /// `0x2000_0000`.
+ SZ_512M,
+ /// `0x4000_0000`.
+ SZ_1G,
+ /// `0x8000_0000`.
+ SZ_2G,
+ );
+ };
+
+ (@internal [$($type:ty),*] $($names_and_metas:tt)*) => {
+ define_sizes!(@consts_and_trait $($names_and_metas)*);
+ define_sizes!(@impls [$($type),*] $($names_and_metas)*);
+ };
+
+ (@consts_and_trait $($(#[$meta:meta])* $name:ident,)*) => {
+ $(
+ $(#[$meta])*
+ pub const $name: usize = bindings::$name as usize;
+ )*
+
+ /// Size constants for device address spaces.
+ ///
+ /// Implemented for [`u32`], [`u64`], and [`usize`] so drivers can
+ /// choose the width that matches their hardware. All `SZ_*` values fit
+ /// in a [`u32`], so all implementations are lossless.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::sizes::SizeConstants;
+ ///
+ /// let gpu_heap = 14 * u64::SZ_1M;
+ /// let mmio_window = u32::SZ_16M;
+ /// ```
+ pub trait SizeConstants {
+ $(
+ $(#[$meta])*
+ const $name: Self;
+ )*
+ }
+ };
+
+ (@impls [] $($(#[$meta:meta])* $name:ident,)*) => {};
+
+ (@impls [$first:ty $(, $rest:ty)*] $($(#[$meta:meta])* $name:ident,)*) => {
+ impl SizeConstants for $first {
+ $(
+ const $name: Self = {
+ assert!((self::$name as u128) <= (<$first>::MAX as u128));
+ self::$name as $first
+ };
+ )*
+ }
+
+ define_sizes!(@impls [$($rest),*] $($(#[$meta])* $name,)*);
+ };
+}
-/// 0x00000400
-pub const SZ_1K: usize = bindings::SZ_1K as usize;
-/// 0x00000800
-pub const SZ_2K: usize = bindings::SZ_2K as usize;
-/// 0x00001000
-pub const SZ_4K: usize = bindings::SZ_4K as usize;
-/// 0x00002000
-pub const SZ_8K: usize = bindings::SZ_8K as usize;
-/// 0x00004000
-pub const SZ_16K: usize = bindings::SZ_16K as usize;
-/// 0x00008000
-pub const SZ_32K: usize = bindings::SZ_32K as usize;
-/// 0x00010000
-pub const SZ_64K: usize = bindings::SZ_64K as usize;
-/// 0x00020000
-pub const SZ_128K: usize = bindings::SZ_128K as usize;
-/// 0x00040000
-pub const SZ_256K: usize = bindings::SZ_256K as usize;
-/// 0x00080000
-pub const SZ_512K: usize = bindings::SZ_512K as usize;
-/// 0x00100000
-pub const SZ_1M: usize = bindings::SZ_1M as usize;
-/// 0x00200000
-pub const SZ_2M: usize = bindings::SZ_2M as usize;
-/// 0x00400000
-pub const SZ_4M: usize = bindings::SZ_4M as usize;
-/// 0x00800000
-pub const SZ_8M: usize = bindings::SZ_8M as usize;
-/// 0x01000000
-pub const SZ_16M: usize = bindings::SZ_16M as usize;
-/// 0x02000000
-pub const SZ_32M: usize = bindings::SZ_32M as usize;
-/// 0x04000000
-pub const SZ_64M: usize = bindings::SZ_64M as usize;
-/// 0x08000000
-pub const SZ_128M: usize = bindings::SZ_128M as usize;
-/// 0x10000000
-pub const SZ_256M: usize = bindings::SZ_256M as usize;
-/// 0x20000000
-pub const SZ_512M: usize = bindings::SZ_512M as usize;
-/// 0x40000000
-pub const SZ_1G: usize = bindings::SZ_1G as usize;
-/// 0x80000000
-pub const SZ_2G: usize = bindings::SZ_2G as usize;
+define_sizes!(u32, u64, usize);
diff --git a/rust/kernel/slice.rs b/rust/kernel/slice.rs
deleted file mode 100644
index ca2cde135061..000000000000
--- a/rust/kernel/slice.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-//! Additional (and temporary) slice helpers.
-
-/// Extension trait providing a portable version of [`as_flattened`] and
-/// [`as_flattened_mut`].
-///
-/// In Rust 1.80, the previously unstable `slice::flatten` family of methods
-/// have been stabilized and renamed from `flatten` to `as_flattened`.
-///
-/// This creates an issue for as long as the MSRV is < 1.80, as the same functionality is provided
-/// by different methods depending on the compiler version.
-///
-/// This extension trait solves this by abstracting `as_flatten` and calling the correct method
-/// depending on the Rust version.
-///
-/// This trait can be removed once the MSRV passes 1.80.
-///
-/// [`as_flattened`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened
-/// [`as_flattened_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened_mut
-#[cfg(not(CONFIG_RUSTC_HAS_SLICE_AS_FLATTENED))]
-pub trait AsFlattened<T> {
- /// Takes a `&[[T; N]]` and flattens it to a `&[T]`.
- ///
- /// This is an portable layer on top of [`as_flattened`]; see its documentation for details.
- ///
- /// [`as_flattened`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened
- fn as_flattened(&self) -> &[T];
-
- /// Takes a `&mut [[T; N]]` and flattens it to a `&mut [T]`.
- ///
- /// This is an portable layer on top of [`as_flattened_mut`]; see its documentation for details.
- ///
- /// [`as_flattened_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.as_flattened_mut
- fn as_flattened_mut(&mut self) -> &mut [T];
-}
-
-#[cfg(not(CONFIG_RUSTC_HAS_SLICE_AS_FLATTENED))]
-impl<T, const N: usize> AsFlattened<T> for [[T; N]] {
- #[allow(clippy::incompatible_msrv)]
- fn as_flattened(&self) -> &[T] {
- self.flatten()
- }
-
- #[allow(clippy::incompatible_msrv)]
- fn as_flattened_mut(&mut self) -> &mut [T] {
- self.flatten_mut()
- }
-}
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
deleted file mode 100644
index a57ba14315a0..000000000000
--- a/rust/kernel/static_assert.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-//! Static assert.
-
-/// Static assert (i.e. compile-time assert).
-///
-/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
-///
-/// An optional panic message can be supplied after the expression.
-/// Currently only a string literal without formatting is supported
-/// due to constness limitations of the [`assert!`] macro.
-///
-/// The feature may be added to Rust in the future: see [RFC 2790].
-///
-/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
-/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
-/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
-///
-/// # Examples
-///
-/// ```
-/// static_assert!(42 > 24);
-/// static_assert!(core::mem::size_of::<u8>() == 1);
-///
-/// const X: &[u8] = b"bar";
-/// static_assert!(X[1] == b'a');
-///
-/// const fn f(x: i32) -> i32 {
-/// x + 2
-/// }
-/// static_assert!(f(40) == 42);
-/// static_assert!(f(40) == 42, "f(x) must add 2 to the given input.");
-/// ```
-#[macro_export]
-macro_rules! static_assert {
- ($condition:expr $(,$arg:literal)?) => {
- const _: () = ::core::assert!($condition $(,$arg)?);
- };
-}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 3f8918764640..8311d91549e1 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -189,6 +189,7 @@ macro_rules! b_str {
//
// - error[E0379]: functions in trait impls cannot be declared const
#[inline]
+#[expect(clippy::disallowed_methods, reason = "internal implementation")]
pub const fn as_char_ptr_in_const_context(c_str: &CStr) -> *const c_char {
c_str.as_ptr().cast()
}
@@ -319,6 +320,7 @@ unsafe fn to_bytes_mut(s: &mut CStr) -> &mut [u8] {
impl CStrExt for CStr {
#[inline]
+ #[expect(clippy::disallowed_methods, reason = "internal implementation")]
unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self {
// SAFETY: The safety preconditions are the same as for `CStr::from_ptr`.
unsafe { CStr::from_ptr(ptr.cast()) }
@@ -334,6 +336,7 @@ impl CStrExt for CStr {
}
#[inline]
+ #[expect(clippy::disallowed_methods, reason = "internal implementation")]
fn as_char_ptr(&self) -> *const c_char {
self.as_ptr().cast()
}
@@ -376,19 +379,32 @@ impl AsRef<BStr> for CStr {
}
}
-/// Creates a new [`CStr`] from a string literal.
+/// Creates a new [`CStr`] at compile time.
///
-/// The string literal should not contain any `NUL` bytes.
+/// Rust supports C string literals since Rust 1.77, and they should be used instead of this macro
+/// where possible. This macro exists to allow static *non-literal* C strings to be created at
+/// compile time. This is most often used in other macros.
+///
+/// # Panics
+///
+/// This macro panics if the operand contains an interior `NUL` byte.
///
/// # Examples
///
/// ```
/// # use kernel::c_str;
/// # use kernel::str::CStr;
-/// const MY_CSTR: &CStr = c_str!("My awesome CStr!");
+/// // This is allowed, but `c"literal"` should be preferred for literals.
+/// const BAD: &CStr = c_str!("literal");
+///
+/// // `c_str!` is still needed for static non-literal C strings.
+/// const GOOD: &CStr = c_str!(concat!(file!(), ":", line!(), ": My CStr!"));
/// ```
#[macro_export]
macro_rules! c_str {
+ // NB: We could write `($str:lit) => compile_error!("use a C string literal instead");` here but
+ // that would trigger when the literal is at the top of several macro expansions. That would be
+ // too limiting to macro authors.
($str:expr) => {{
const S: &str = concat!($str, "\0");
const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) {
@@ -828,7 +844,10 @@ impl CString {
f.write_str("\0")?;
// SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is
- // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`.
+ // `buf`'s capacity. The `Formatter` is created with `size` as its limit, and the `?`
+ // operators on `write_fmt` and `write_str` above ensure that if writing exceeds this
+ // limit, an error is returned early. The contents of the buffer have been initialised
+ // by writes to `f`.
unsafe { buf.inc_len(f.bytes_written()) };
// Check that there are no `NUL` bytes before the end.
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index 921e19333b89..18d6c0d62ce0 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -128,7 +128,7 @@ mod std_vendor;
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
-#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
+#[derive(core::marker::CoercePointee)]
pub struct Arc<T: ?Sized> {
ptr: NonNull<ArcInner<T>>,
// NB: this informs dropck that objects of type `ArcInner<T>` may be used in `<Arc<T> as
@@ -182,15 +182,6 @@ impl<T: ?Sized> ArcInner<T> {
}
}
-// This is to allow coercion from `Arc<T>` to `Arc<U>` if `T` can be converted to the
-// dynamically-sized type (DST) `U`.
-#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
-impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {}
-
-// This is to allow `Arc<U>` to be dispatched on when `Arc<T>` can be coerced into `Arc<U>`.
-#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
-impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {}
-
// SAFETY: It is safe to send `Arc<T>` to another thread when the underlying `T` is `Sync` because
// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
// `T` to be `Send` because any thread that has an `Arc<T>` may ultimately access `T` using a
@@ -547,20 +538,12 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
-#[cfg_attr(CONFIG_RUSTC_HAS_COERCE_POINTEE, derive(core::marker::CoercePointee))]
+#[derive(core::marker::CoercePointee)]
pub struct ArcBorrow<'a, T: ?Sized + 'a> {
inner: NonNull<ArcInner<T>>,
_p: PhantomData<&'a ()>,
}
-// This is to allow `ArcBorrow<U>` to be dispatched on when `ArcBorrow<T>` can be coerced into
-// `ArcBorrow<U>`.
-#[cfg(not(CONFIG_RUSTC_HAS_COERCE_POINTEE))]
-impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
- for ArcBorrow<'_, T>
-{
-}
-
impl<T: ?Sized> Clone for ArcBorrow<'_, T> {
fn clone(&self) -> Self {
*self
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
index cc907fb531bc..049c8a4d45d8 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -6,16 +6,15 @@
use crate::{
bindings,
- ffi::{c_int, c_long, c_uint},
mm::MmWithUser,
pid_namespace::PidNamespace,
+ prelude::*,
sync::aref::ARef,
types::{NotThreadSafe, Opaque},
};
use core::{
- cmp::{Eq, PartialEq},
ops::Deref,
- ptr,
+ ptr, //
};
/// A sentinel value used for infinite timeouts.
@@ -419,7 +418,7 @@ pub fn might_sleep() {
let file = kernel::file_from_location(loc);
// SAFETY: `file.as_ptr()` is valid for reading and guaranteed to be nul-terminated.
- unsafe { crate::bindings::__might_sleep(file.as_ptr().cast(), loc.line() as i32) }
+ unsafe { crate::bindings::__might_sleep(file.as_char_ptr(), loc.line() as i32) }
}
// SAFETY: Always safe to call.
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index 6ea98dfcd027..363e93cbb139 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -60,7 +60,13 @@ pub fn msecs_to_jiffies(msecs: Msecs) -> Jiffies {
/// cases the user of the clock has to decide which clock is best suited for the
/// purpose. In most scenarios clock [`Monotonic`] is the best choice as it
/// provides a accurate monotonic notion of time (leap second smearing ignored).
-pub trait ClockSource {
+///
+/// # Safety
+///
+/// Implementers must ensure that `ktime_get()` returns a value in the inclusive range
+/// `0..=KTIME_MAX` (i.e., greater than or equal to 0 and less than or equal to
+/// `KTIME_MAX`, where `KTIME_MAX` equals `i64::MAX`).
+pub unsafe trait ClockSource {
/// The kernel clock ID associated with this clock source.
///
/// This constant corresponds to the C side `clockid_t` value.
@@ -68,7 +74,7 @@ pub trait ClockSource {
/// Get the current time from the clock source.
///
- /// The function must return a value in the range from 0 to `KTIME_MAX`.
+ /// The function must return a value in the range `0..=KTIME_MAX`.
fn ktime_get() -> bindings::ktime_t;
}
@@ -85,7 +91,9 @@ pub trait ClockSource {
/// count time that the system is suspended.
pub struct Monotonic;
-impl ClockSource for Monotonic {
+// SAFETY: The kernel's `ktime_get()` is guaranteed to return a value
+// in `0..=KTIME_MAX`.
+unsafe impl ClockSource for Monotonic {
const ID: bindings::clockid_t = bindings::CLOCK_MONOTONIC as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@@ -110,7 +118,9 @@ impl ClockSource for Monotonic {
/// the clock will experience discontinuity around leap second adjustment.
pub struct RealTime;
-impl ClockSource for RealTime {
+// SAFETY: The kernel's `ktime_get_real()` is guaranteed to return a value
+// in `0..=KTIME_MAX`.
+unsafe impl ClockSource for RealTime {
const ID: bindings::clockid_t = bindings::CLOCK_REALTIME as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@@ -128,7 +138,9 @@ impl ClockSource for RealTime {
/// discontinuities if the time is changed using settimeofday(2) or similar.
pub struct BootTime;
-impl ClockSource for BootTime {
+// SAFETY: The kernel's `ktime_get_boottime()` is guaranteed to return a value
+// in `0..=KTIME_MAX`.
+unsafe impl ClockSource for BootTime {
const ID: bindings::clockid_t = bindings::CLOCK_BOOTTIME as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@@ -150,7 +162,9 @@ impl ClockSource for BootTime {
/// The acronym TAI refers to International Atomic Time.
pub struct Tai;
-impl ClockSource for Tai {
+// SAFETY: The kernel's `ktime_get_clocktai()` is guaranteed to return a value
+// in `0..=KTIME_MAX`.
+unsafe impl ClockSource for Tai {
const ID: bindings::clockid_t = bindings::CLOCK_TAI as bindings::clockid_t;
fn ktime_get() -> bindings::ktime_t {
@@ -363,6 +377,12 @@ impl Delta {
/// A span of time equal to zero.
pub const ZERO: Self = Self { nanos: 0 };
+ /// Create a new [`Delta`] from a number of nanoseconds.
+ #[inline]
+ pub const fn from_nanos(nanos: i64) -> Self {
+ Self { nanos }
+ }
+
/// Create a new [`Delta`] from a number of microseconds.
///
/// The `micros` can range from -9_223_372_036_854_775 to 9_223_372_036_854_775.
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 856d2d929a00..2d7f1131a813 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -66,6 +66,342 @@
//!
//! A `restart` operation on a timer in the **stopped** state is equivalent to a
//! `start` operation.
+//!
+//! When a type implements both `HrTimerPointer` and `Clone`, it is possible to
+//! issue the `start` operation while the timer is in the **started** state. In
+//! this case the `start` operation is equivalent to the `restart` operation.
+//!
+//! # Examples
+//!
+//! ## Using an intrusive timer living in a [`Box`]
+//!
+//! ```
+//! # use kernel::{
+//! # alloc::flags,
+//! # impl_has_hr_timer,
+//! # prelude::*,
+//! # sync::{
+//! # atomic::{ordering, Atomic},
+//! # completion::Completion,
+//! # Arc,
+//! # },
+//! # time::{
+//! # hrtimer::{
+//! # RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer,
+//! # HrTimerRestart, HrTimerCallbackContext
+//! # },
+//! # Delta, Monotonic,
+//! # },
+//! # };
+//!
+//! #[pin_data]
+//! struct Shared {
+//! #[pin]
+//! flag: Atomic<u64>,
+//! #[pin]
+//! cond: Completion,
+//! }
+//!
+//! impl Shared {
+//! fn new() -> impl PinInit<Self> {
+//! pin_init!(Self {
+//! flag <- Atomic::new(0),
+//! cond <- Completion::new(),
+//! })
+//! }
+//! }
+//!
+//! #[pin_data]
+//! struct BoxIntrusiveHrTimer {
+//! #[pin]
+//! timer: HrTimer<Self>,
+//! shared: Arc<Shared>,
+//! }
+//!
+//! impl BoxIntrusiveHrTimer {
+//! fn new() -> impl PinInit<Self, kernel::error::Error> {
+//! try_pin_init!(Self {
+//! timer <- HrTimer::new(),
+//! shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,
+//! })
+//! }
+//! }
+//!
+//! impl HrTimerCallback for BoxIntrusiveHrTimer {
+//! type Pointer<'a> = Pin<KBox<Self>>;
+//!
+//! fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
+//! pr_info!("Timer called\n");
+//!
+//! let flag = this.shared.flag.fetch_add(1, ordering::Full);
+//! this.shared.cond.complete_all();
+//!
+//! if flag == 4 {
+//! HrTimerRestart::NoRestart
+//! } else {
+//! HrTimerRestart::Restart
+//! }
+//! }
+//! }
+//!
+//! impl_has_hr_timer! {
+//! impl HasHrTimer<Self> for BoxIntrusiveHrTimer {
+//! mode: RelativeMode<Monotonic>, field: self.timer
+//! }
+//! }
+//!
+//! let has_timer = Box::pin_init(BoxIntrusiveHrTimer::new(), GFP_KERNEL)?;
+//! let shared = has_timer.shared.clone();
+//! let _handle = has_timer.start(Delta::from_micros(200));
+//!
+//! while shared.flag.load(ordering::Relaxed) != 5 {
+//! shared.cond.wait_for_completion();
+//! }
+//!
+//! pr_info!("Counted to 5\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! ## Using an intrusive timer in an [`Arc`]
+//!
+//! ```
+//! # use kernel::{
+//! # alloc::flags,
+//! # impl_has_hr_timer,
+//! # prelude::*,
+//! # sync::{
+//! # atomic::{ordering, Atomic},
+//! # completion::Completion,
+//! # Arc, ArcBorrow,
+//! # },
+//! # time::{
+//! # hrtimer::{
+//! # RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
+//! # HasHrTimer, HrTimerCallbackContext
+//! # },
+//! # Delta, Monotonic,
+//! # },
+//! # };
+//!
+//! #[pin_data]
+//! struct ArcIntrusiveHrTimer {
+//! #[pin]
+//! timer: HrTimer<Self>,
+//! #[pin]
+//! flag: Atomic<u64>,
+//! #[pin]
+//! cond: Completion,
+//! }
+//!
+//! impl ArcIntrusiveHrTimer {
+//! fn new() -> impl PinInit<Self> {
+//! pin_init!(Self {
+//! timer <- HrTimer::new(),
+//! flag <- Atomic::new(0),
+//! cond <- Completion::new(),
+//! })
+//! }
+//! }
+//!
+//! impl HrTimerCallback for ArcIntrusiveHrTimer {
+//! type Pointer<'a> = Arc<Self>;
+//!
+//! fn run(
+//! this: ArcBorrow<'_, Self>,
+//! _ctx: HrTimerCallbackContext<'_, Self>,
+//! ) -> HrTimerRestart {
+//! pr_info!("Timer called\n");
+//!
+//! let flag = this.flag.fetch_add(1, ordering::Full);
+//! this.cond.complete_all();
+//!
+//! if flag == 4 {
+//! HrTimerRestart::NoRestart
+//! } else {
+//! HrTimerRestart::Restart
+//! }
+//! }
+//! }
+//!
+//! impl_has_hr_timer! {
+//! impl HasHrTimer<Self> for ArcIntrusiveHrTimer {
+//! mode: RelativeMode<Monotonic>, field: self.timer
+//! }
+//! }
+//!
+//! let has_timer = Arc::pin_init(ArcIntrusiveHrTimer::new(), GFP_KERNEL)?;
+//! let _handle = has_timer.clone().start(Delta::from_micros(200));
+//!
+//! while has_timer.flag.load(ordering::Relaxed) != 5 {
+//! has_timer.cond.wait_for_completion();
+//! }
+//!
+//! pr_info!("Counted to 5\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! ## Using a stack-based timer
+//!
+//! ```
+//! # use kernel::{
+//! # impl_has_hr_timer,
+//! # prelude::*,
+//! # sync::{
+//! # atomic::{ordering, Atomic},
+//! # completion::Completion,
+//! # },
+//! # time::{
+//! # hrtimer::{
+//! # ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
+//! # HasHrTimer, RelativeMode, HrTimerCallbackContext
+//! # },
+//! # Delta, Monotonic,
+//! # },
+//! # };
+//! # use pin_init::stack_pin_init;
+//!
+//! #[pin_data]
+//! struct IntrusiveHrTimer {
+//! #[pin]
+//! timer: HrTimer<Self>,
+//! #[pin]
+//! flag: Atomic<u64>,
+//! #[pin]
+//! cond: Completion,
+//! }
+//!
+//! impl IntrusiveHrTimer {
+//! fn new() -> impl PinInit<Self> {
+//! pin_init!(Self {
+//! timer <- HrTimer::new(),
+//! flag <- Atomic::new(0),
+//! cond <- Completion::new(),
+//! })
+//! }
+//! }
+//!
+//! impl HrTimerCallback for IntrusiveHrTimer {
+//! type Pointer<'a> = Pin<&'a Self>;
+//!
+//! fn run(this: Pin<&Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
+//! pr_info!("Timer called\n");
+//!
+//! this.flag.store(1, ordering::Release);
+//! this.cond.complete_all();
+//!
+//! HrTimerRestart::NoRestart
+//! }
+//! }
+//!
+//! impl_has_hr_timer! {
+//! impl HasHrTimer<Self> for IntrusiveHrTimer {
+//! mode: RelativeMode<Monotonic>, field: self.timer
+//! }
+//! }
+//!
+//! stack_pin_init!( let has_timer = IntrusiveHrTimer::new() );
+//! has_timer.as_ref().start_scoped(Delta::from_micros(200), || {
+//! while has_timer.flag.load(ordering::Relaxed) != 1 {
+//! has_timer.cond.wait_for_completion();
+//! }
+//! });
+//!
+//! pr_info!("Flag raised\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! ## Using a mutable stack-based timer
+//!
+//! ```
+//! # use kernel::{
+//! # alloc::flags,
+//! # impl_has_hr_timer,
+//! # prelude::*,
+//! # sync::{
+//! # atomic::{ordering, Atomic},
+//! # completion::Completion,
+//! # Arc,
+//! # },
+//! # time::{
+//! # hrtimer::{
+//! # ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,
+//! # HasHrTimer, RelativeMode, HrTimerCallbackContext
+//! # },
+//! # Delta, Monotonic,
+//! # },
+//! # };
+//! # use pin_init::stack_try_pin_init;
+//!
+//! #[pin_data]
+//! struct Shared {
+//! #[pin]
+//! flag: Atomic<u64>,
+//! #[pin]
+//! cond: Completion,
+//! }
+//!
+//! impl Shared {
+//! fn new() -> impl PinInit<Self> {
+//! pin_init!(Self {
+//! flag <- Atomic::new(0),
+//! cond <- Completion::new(),
+//! })
+//! }
+//! }
+//!
+//! #[pin_data]
+//! struct IntrusiveHrTimer {
+//! #[pin]
+//! timer: HrTimer<Self>,
+//! shared: Arc<Shared>,
+//! }
+//!
+//! impl IntrusiveHrTimer {
+//! fn new() -> impl PinInit<Self, kernel::error::Error> {
+//! try_pin_init!(Self {
+//! timer <- HrTimer::new(),
+//! shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,
+//! })
+//! }
+//! }
+//!
+//! impl HrTimerCallback for IntrusiveHrTimer {
+//! type Pointer<'a> = Pin<&'a mut Self>;
+//!
+//! fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {
+//! pr_info!("Timer called\n");
+//!
+//! let flag = this.shared.flag.fetch_add(1, ordering::Full);
+//! this.shared.cond.complete_all();
+//!
+//! if flag == 4 {
+//! HrTimerRestart::NoRestart
+//! } else {
+//! HrTimerRestart::Restart
+//! }
+//! }
+//! }
+//!
+//! impl_has_hr_timer! {
+//! impl HasHrTimer<Self> for IntrusiveHrTimer {
+//! mode: RelativeMode<Monotonic>, field: self.timer
+//! }
+//! }
+//!
+//! stack_try_pin_init!( let has_timer =? IntrusiveHrTimer::new() );
+//! let shared = has_timer.shared.clone();
+//!
+//! has_timer.as_mut().start_scoped(Delta::from_micros(200), || {
+//! while shared.flag.load(ordering::Relaxed) != 5 {
+//! shared.cond.wait_for_completion();
+//! }
+//! });
+//!
+//! pr_info!("Counted to 5\n");
+//! # Ok::<(), kernel::error::Error>(())
+//! ```
+//!
+//! [`Arc`]: kernel::sync::Arc
use super::{ClockSource, Delta, Instant};
use crate::{prelude::*, types::Opaque};
diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs
index 5711580c9f9b..654b5ede2fe2 100644
--- a/rust/kernel/transmute.rs
+++ b/rust/kernel/transmute.rs
@@ -49,7 +49,6 @@ pub unsafe trait FromBytes {
let slice_ptr = bytes.as_ptr().cast::<Self>();
let size = size_of::<Self>();
- #[allow(clippy::incompatible_msrv)]
if bytes.len() == size && slice_ptr.is_aligned() {
// SAFETY: Size and alignment were just checked.
unsafe { Some(&*slice_ptr) }
@@ -67,16 +66,9 @@ pub unsafe trait FromBytes {
where
Self: Sized,
{
- if bytes.len() < size_of::<Self>() {
- None
- } else {
- // PANIC: We checked that `bytes.len() >= size_of::<Self>`, thus `split_at` cannot
- // panic.
- // TODO: replace with `split_at_checked` once the MSRV is >= 1.80.
- let (prefix, remainder) = bytes.split_at(size_of::<Self>());
+ let (prefix, remainder) = bytes.split_at_checked(size_of::<Self>())?;
- Self::from_bytes(prefix).map(|s| (s, remainder))
- }
+ Self::from_bytes(prefix).map(|s| (s, remainder))
}
/// Converts a mutable slice of bytes to a reference to `Self`.
@@ -92,7 +84,6 @@ pub unsafe trait FromBytes {
let slice_ptr = bytes.as_mut_ptr().cast::<Self>();
let size = size_of::<Self>();
- #[allow(clippy::incompatible_msrv)]
if bytes.len() == size && slice_ptr.is_aligned() {
// SAFETY: Size and alignment were just checked.
unsafe { Some(&mut *slice_ptr) }
@@ -110,16 +101,9 @@ pub unsafe trait FromBytes {
where
Self: AsBytes + Sized,
{
- if bytes.len() < size_of::<Self>() {
- None
- } else {
- // PANIC: We checked that `bytes.len() >= size_of::<Self>`, thus `split_at_mut` cannot
- // panic.
- // TODO: replace with `split_at_mut_checked` once the MSRV is >= 1.80.
- let (prefix, remainder) = bytes.split_at_mut(size_of::<Self>());
+ let (prefix, remainder) = bytes.split_at_mut_checked(size_of::<Self>())?;
- Self::from_bytes_mut(prefix).map(|s| (s, remainder))
- }
+ Self::from_bytes_mut(prefix).map(|s| (s, remainder))
}
/// Creates an owned instance of `Self` by copying `bytes`.
@@ -149,16 +133,9 @@ pub unsafe trait FromBytes {
where
Self: Sized,
{
- if bytes.len() < size_of::<Self>() {
- None
- } else {
- // PANIC: We checked that `bytes.len() >= size_of::<Self>`, thus `split_at` cannot
- // panic.
- // TODO: replace with `split_at_checked` once the MSRV is >= 1.80.
- let (prefix, remainder) = bytes.split_at(size_of::<Self>());
+ let (prefix, remainder) = bytes.split_at_checked(size_of::<Self>())?;
- Self::from_bytes_copy(prefix).map(|s| (s, remainder))
- }
+ Self::from_bytes_copy(prefix).map(|s| (s, remainder))
}
}
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 9c5e7dbf1632..4329d3c2c2e5 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -11,8 +11,6 @@ use core::{
};
use pin_init::{PinInit, Wrapper, Zeroable};
-pub use crate::sync::aref::{ARef, AlwaysRefCounted};
-
/// Used to transfer ownership to and from foreign (non-Rust) languages.
///
/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 0e1b9a88f4f1..9c17a672cd27 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -18,10 +18,8 @@ use crate::{
to_result, //
},
prelude::*,
- types::{
- AlwaysRefCounted,
- Opaque, //
- },
+ sync::aref::AlwaysRefCounted,
+ types::Opaque,
ThisModule, //
};
use core::{
diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs
index a49d6db28845..46e5f43223fe 100644
--- a/rust/kernel/xarray.rs
+++ b/rust/kernel/xarray.rs
@@ -172,6 +172,7 @@ pub struct StoreError<T> {
}
impl<T> From<StoreError<T>> for Error {
+ #[inline]
fn from(value: StoreError<T>) -> Self {
value.error
}
diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs
index 37ef6a6f2c85..d18fbf4daa0a 100644
--- a/rust/macros/helpers.rs
+++ b/rust/macros/helpers.rs
@@ -49,7 +49,6 @@ pub(crate) fn file() -> String {
}
#[cfg(CONFIG_RUSTC_HAS_SPAN_FILE)]
- #[allow(clippy::incompatible_msrv)]
{
proc_macro::Span::call_site().file()
}
diff --git a/rust/macros/kunit.rs b/rust/macros/kunit.rs
index 6be880d634e2..ae20ed6768f1 100644
--- a/rust/macros/kunit.rs
+++ b/rust/macros/kunit.rs
@@ -87,10 +87,11 @@ pub(crate) fn kunit_tests(test_suite: Ident, mut module: ItemMod) -> Result<Toke
continue;
};
- // TODO: Replace below with `extract_if` when MSRV is bumped above 1.85.
- let before_len = f.attrs.len();
- f.attrs.retain(|attr| !attr.path().is_ident("test"));
- if f.attrs.len() == before_len {
+ if f.attrs
+ .extract_if(.., |attr| attr.path().is_ident("test"))
+ .count()
+ == 0
+ {
processed_items.push(Item::Fn(f));
continue;
}
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 0c36194d9971..2cfd59e0f9e7 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -6,6 +6,9 @@
// and thus add a dependency on `include/config/RUSTC_VERSION_TEXT`, which is
// touched by Kconfig when the version string from the compiler changes.
+// Stable since Rust 1.87.0.
+#![feature(extract_if)]
+//
// Stable since Rust 1.88.0 under a different name, `proc_macro_span_file`,
// which was added in Rust 1.88.0. This is why `cfg_attr` is used here, i.e.
// to avoid depending on the full `proc_macro_span` on Rust >= 1.88.0.
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index e16298e520c7..06c18e207508 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -52,12 +52,7 @@ impl<'a> ModInfoBuilder<'a> {
fn emit_base(&mut self, field: &str, content: &str, builtin: bool, param: bool) {
let string = if builtin {
// Built-in modules prefix their modinfo strings by `module.`.
- format!(
- "{module}.{field}={content}\0",
- module = self.module,
- field = field,
- content = content
- )
+ format!("{module}.{field}={content}\0", module = self.module)
} else {
// Loadable modules' modinfo strings go as-is.
format!("{field}={content}\0")
@@ -109,7 +104,7 @@ impl<'a> ModInfoBuilder<'a> {
}
fn emit_param(&mut self, field: &str, param: &str, content: &str) {
- let content = format!("{param}:{content}", param = param, content = content);
+ let content = format!("{param}:{content}");
self.emit_internal(field, &content, true);
}
diff --git a/rust/pin-init/README.md b/rust/pin-init/README.md
index 6cee6ab1eb57..9095d6661ff6 100644
--- a/rust/pin-init/README.md
+++ b/rust/pin-init/README.md
@@ -160,7 +160,6 @@ actually does the initialization in the correct way. Here are the things to look
```rust
use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
use core::{
- ptr::addr_of_mut,
marker::PhantomPinned,
cell::UnsafeCell,
pin::Pin,
@@ -199,7 +198,7 @@ impl RawFoo {
unsafe {
pin_init_from_closure(move |slot: *mut Self| {
// `slot` contains uninit memory, avoid creating a reference.
- let foo = addr_of_mut!((*slot).foo);
+ let foo = &raw mut (*slot).foo;
let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
// Initialize the `foo`
diff --git a/rust/pin-init/examples/big_struct_in_place.rs b/rust/pin-init/examples/big_struct_in_place.rs
index c05139927486..80f89b5f8fd6 100644
--- a/rust/pin-init/examples/big_struct_in_place.rs
+++ b/rust/pin-init/examples/big_struct_in_place.rs
@@ -1,5 +1,8 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
+
use pin_init::*;
// Struct with size over 1GiB
diff --git a/rust/pin-init/examples/linked_list.rs b/rust/pin-init/examples/linked_list.rs
index 8445a5890cb7..119169e4dc41 100644
--- a/rust/pin-init/examples/linked_list.rs
+++ b/rust/pin-init/examples/linked_list.rs
@@ -2,7 +2,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
use core::{
cell::Cell,
diff --git a/rust/pin-init/examples/mutex.rs b/rust/pin-init/examples/mutex.rs
index 9f295226cd64..d53671f0edb8 100644
--- a/rust/pin-init/examples/mutex.rs
+++ b/rust/pin-init/examples/mutex.rs
@@ -2,7 +2,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#![allow(clippy::missing_safety_doc)]
use core::{
diff --git a/rust/pin-init/examples/pthread_mutex.rs b/rust/pin-init/examples/pthread_mutex.rs
index 4e082ec7d5de..f3b5cc9b7134 100644
--- a/rust/pin-init/examples/pthread_mutex.rs
+++ b/rust/pin-init/examples/pthread_mutex.rs
@@ -3,7 +3,8 @@
// inspired by <https://github.com/nbdd0121/pin-init/blob/trunk/examples/pthread_mutex.rs>
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#[cfg(not(windows))]
mod pthread_mtx {
diff --git a/rust/pin-init/examples/static_init.rs b/rust/pin-init/examples/static_init.rs
index 0e165daa9798..f7e53d1a5ae6 100644
--- a/rust/pin-init/examples/static_init.rs
+++ b/rust/pin-init/examples/static_init.rs
@@ -2,7 +2,8 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#![allow(unused_imports)]
use core::{
diff --git a/rust/pin-init/internal/src/init.rs b/rust/pin-init/internal/src/init.rs
index 2fe918f4d82a..daa3f1c6466e 100644
--- a/rust/pin-init/internal/src/init.rs
+++ b/rust/pin-init/internal/src/init.rs
@@ -173,6 +173,12 @@ pub(crate) fn expand(
};
// SAFETY: TODO
let init = unsafe { ::pin_init::#init_from_closure::<_, #error>(init) };
+ // FIXME: this let binding is required to avoid a compiler error (cycle when computing the
+ // opaque type returned by this function) before Rust 1.81. Remove after MSRV bump.
+ #[allow(
+ clippy::let_and_return,
+ reason = "some clippy versions warn about the let binding"
+ )]
init
}})
}
@@ -264,7 +270,7 @@ fn init_fields(
{
#value_prep
// SAFETY: TODO
- unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
+ unsafe { #write(&raw mut (*#slot).#ident, #value_ident) };
}
#(#cfgs)*
#[allow(unused_variables)]
@@ -287,7 +293,7 @@ fn init_fields(
// return when an error/panic occurs.
// - We also use `#data` to require the correct trait (`Init` or `PinInit`)
// for `#ident`.
- unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? };
+ unsafe { #data.#ident(&raw mut (*#slot).#ident, #init)? };
},
quote! {
// SAFETY: TODO
@@ -302,7 +308,7 @@ fn init_fields(
unsafe {
::pin_init::Init::__init(
#init,
- ::core::ptr::addr_of_mut!((*#slot).#ident),
+ &raw mut (*#slot).#ident,
)?
};
},
@@ -342,7 +348,7 @@ fn init_fields(
// SAFETY: We forget the guard later when initialization has succeeded.
let #guard = unsafe {
::pin_init::__internal::DropGuard::new(
- ::core::ptr::addr_of_mut!((*slot).#ident)
+ &raw mut (*slot).#ident
)
};
});
diff --git a/rust/pin-init/internal/src/lib.rs b/rust/pin-init/internal/src/lib.rs
index 08372c8f65f0..b08dfe003031 100644
--- a/rust/pin-init/internal/src/lib.rs
+++ b/rust/pin-init/internal/src/lib.rs
@@ -6,7 +6,7 @@
//! `pin-init` proc macros.
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
// Documentation is done in the pin-init crate instead.
#![allow(missing_docs)]
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index fe4c85ae3f02..64eec095c859 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -172,7 +172,6 @@
//! # #![feature(extern_types)]
//! use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
//! use core::{
-//! ptr::addr_of_mut,
//! marker::PhantomPinned,
//! cell::UnsafeCell,
//! pin::Pin,
@@ -211,7 +210,7 @@
//! unsafe {
//! pin_init_from_closure(move |slot: *mut Self| {
//! // `slot` contains uninit memory, avoid creating a reference.
-//! let foo = addr_of_mut!((*slot).foo);
+//! let foo = &raw mut (*slot).foo;
//! let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
//!
//! // Initialize the `foo`
@@ -264,12 +263,10 @@
//! [`impl Init<T, E>`]: crate::Init
//! [Rust-for-Linux]: https://rust-for-linux.com/
-#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))]
+#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))]
#![cfg_attr(
- all(
- any(feature = "alloc", feature = "std"),
- not(RUSTC_NEW_UNINIT_IS_STABLE)
- ),
+ all(any(feature = "alloc", feature = "std"), USE_RUSTC_FEATURES),
feature(new_uninit)
)]
#![forbid(missing_docs, unsafe_op_in_unsafe_fn)]
@@ -279,6 +276,8 @@
all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED),
feature(unsafe_pinned)
)]
+#![cfg_attr(all(USE_RUSTC_FEATURES, doc), allow(internal_features))]
+#![cfg_attr(all(USE_RUSTC_FEATURES, doc), feature(rustdoc_internals))]
use core::{
cell::UnsafeCell,
@@ -755,7 +754,7 @@ macro_rules! stack_try_pin_init {
///
/// ```rust
/// # use pin_init::*;
-/// # use core::{ptr::addr_of_mut, marker::PhantomPinned};
+/// # use core::marker::PhantomPinned;
/// #[pin_data]
/// #[derive(Zeroable)]
/// struct Buf {
@@ -769,7 +768,7 @@ macro_rules! stack_try_pin_init {
/// let init = pin_init!(&this in Buf {
/// buf: [0; 64],
/// // SAFETY: TODO.
-/// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() },
+/// ptr: unsafe { (&raw mut (*this.as_ptr()).buf).cast() },
/// pin: PhantomPinned,
/// });
/// let init = pin_init!(Buf {
@@ -1147,9 +1146,12 @@ pub const unsafe fn cast_pin_init<T, U, E>(init: impl PinInit<T, E>) -> impl Pin
// SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety
// requirements.
let res = unsafe { pin_init_from_closure(|ptr: *mut U| init.__pinned_init(ptr.cast::<T>())) };
- // FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a
- // cycle when computing the type returned by this function)
- #[allow(clippy::let_and_return)]
+ // FIXME: this let binding is required to avoid a compiler error (cycle when computing the opaque
+ // type returned by this function) before Rust 1.81. Remove after MSRV bump.
+ #[allow(
+ clippy::let_and_return,
+ reason = "some clippy versions warn about the let binding"
+ )]
res
}
@@ -1163,9 +1165,12 @@ pub const unsafe fn cast_init<T, U, E>(init: impl Init<T, E>) -> impl Init<U, E>
// SAFETY: initialization delegated to a valid initializer. Cast is valid by function safety
// requirements.
let res = unsafe { init_from_closure(|ptr: *mut U| init.__init(ptr.cast::<T>())) };
- // FIXME: remove the let statement once the nightly-MSRV allows it (1.78 otherwise encounters a
- // cycle when computing the type returned by this function)
- #[allow(clippy::let_and_return)]
+ // FIXME: this let binding is required to avoid a compiler error (cycle when computing the opaque
+ // type returned by this function) before Rust 1.81. Remove after MSRV bump.
+ #[allow(
+ clippy::let_and_return,
+ reason = "some clippy versions warn about the let binding"
+ )]
res
}
@@ -1610,13 +1615,6 @@ impl_zeroable! {
// SAFETY: `T: Zeroable` and `UnsafeCell` is `repr(transparent)`.
{<T: ?Sized + Zeroable>} UnsafeCell<T>,
- // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee:
- // <https://doc.rust-lang.org/stable/std/option/index.html#representation>).
- Option<NonZeroU8>, Option<NonZeroU16>, Option<NonZeroU32>, Option<NonZeroU64>,
- Option<NonZeroU128>, Option<NonZeroUsize>,
- Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>,
- Option<NonZeroI128>, Option<NonZeroIsize>,
-
// SAFETY: `null` pointer is valid.
//
// We cannot use `T: ?Sized`, since the VTABLE pointer part of fat pointers is not allowed to be
@@ -1635,8 +1633,14 @@ impl_zeroable! {
}
macro_rules! impl_tuple_zeroable {
- ($(,)?) => {};
+ ($first:ident, $(,)?) => {
+ #[cfg_attr(all(USE_RUSTC_FEATURES, doc), doc(fake_variadic))]
+ /// Implemented for tuples up to 10 items long.
+ // SAFETY: All elements are zeroable and padding can be zero.
+ unsafe impl<$first: Zeroable> Zeroable for ($first,) {}
+ };
($first:ident, $($t:ident),* $(,)?) => {
+ #[cfg_attr(doc, doc(hidden))]
// SAFETY: All elements are zeroable and padding can be zero.
unsafe impl<$first: Zeroable, $($t: Zeroable),*> Zeroable for ($first, $($t),*) {}
impl_tuple_zeroable!($($t),* ,);
@@ -1651,7 +1655,16 @@ macro_rules! impl_fn_zeroable_option {
$(impl_fn_zeroable_option!({unsafe extern $abi} $args);)*
};
({$($prefix:tt)*} {$(,)?}) => {};
+ ({$($prefix:tt)*} {$ret:ident, $arg:ident $(,)?}) => {
+ #[cfg_attr(all(USE_RUSTC_FEATURES, doc), doc(fake_variadic))]
+ /// Implemented for function pointers with up to 20 arity.
+ // SAFETY: function pointers are part of the option layout optimization:
+ // <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+ unsafe impl<$ret, $arg> ZeroableOption for $($prefix)* fn($arg) -> $ret {}
+ impl_fn_zeroable_option!({$($prefix)*} {$arg,});
+ };
({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => {
+ #[cfg_attr(doc, doc(hidden))]
// SAFETY: function pointers are part of the option layout optimization:
// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {}
@@ -1661,6 +1674,20 @@ macro_rules! impl_fn_zeroable_option {
impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U });
+macro_rules! impl_non_zero_int_zeroable_option {
+ ($($int:ty),* $(,)?) => {
+ // SAFETY: Safety comment written in the macro invocation.
+ $(unsafe impl ZeroableOption for $int {})*
+ };
+}
+
+impl_non_zero_int_zeroable_option! {
+ // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee:
+ // <https://doc.rust-lang.org/stable/std/option/index.html#representation>).
+ NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
+ NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize,
+}
+
/// This trait allows creating an instance of `Self` which contains exactly one
/// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).
///
diff --git a/rust/uapi/lib.rs b/rust/uapi/lib.rs
index 1d5fd9efb93e..b8a515de31ca 100644
--- a/rust/uapi/lib.rs
+++ b/rust/uapi/lib.rs
@@ -8,10 +8,6 @@
//! userspace APIs.
#![no_std]
-// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
-#![cfg_attr(test, allow(deref_nullptr))]
-#![cfg_attr(test, allow(unaligned_references))]
-#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
#![allow(
clippy::all,
clippy::cast_lossless,
@@ -28,6 +24,7 @@
unsafe_op_in_unsafe_fn
)]
#![cfg_attr(CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES, allow(unnecessary_transmutes))]
+#![feature(cfi_encoding)]
// Manual definition of blocklisted types.
type __kernel_size_t = usize;
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 3652b85be545..57cff77c2897 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -310,18 +310,13 @@ $(obj)/%.lst: $(obj)/%.c FORCE
# The features in this list are the ones allowed for non-`rust/` code.
#
-# - Stable since Rust 1.79.0: `feature(slice_ptr_len)`.
-# - Stable since Rust 1.81.0: `feature(lint_reasons)`.
-# - Stable since Rust 1.82.0: `feature(asm_const)`,
-# `feature(offset_of_nested)`, `feature(raw_ref_op)`.
-# - Stable since Rust 1.84.0: `feature(strict_provenance)`.
# - Stable since Rust 1.87.0: `feature(asm_goto)`.
# - Expected to become stable: `feature(arbitrary_self_types)`.
# - To be determined: `feature(used_with_arg)`.
#
# Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
# the unstable features in use.
-rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op,slice_ptr_len,strict_provenance,used_with_arg
+rust_allowed_features := arbitrary_self_types,asm_goto,used_with_arg
# `--out-dir` is required to avoid temporaries being created by `rustc` in the
# current working directory, which may be not accessible in the out-of-tree
@@ -334,7 +329,6 @@ rust_common_cmd = \
-Zcrate-attr='feature($(rust_allowed_features))' \
-Zunstable-options --extern pin_init --extern kernel \
--crate-type rlib -L $(objtree)/rust/ \
- --crate-name $(basename $(notdir $@)) \
--sysroot=/dev/null \
--out-dir $(dir $@) --emit=dep-info=$(depfile)
@@ -347,7 +341,12 @@ rust_common_cmd = \
# would not match each other.
quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
- cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $< $(cmd_objtool)
+ cmd_rustc_o_rs = $(rust_common_cmd) --emit=$(if $(CONFIG_RUST_INLINE_HELPERS),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) $< \
+ $(if $(CONFIG_RUST_INLINE_HELPERS),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \
+ $(objtree)/rust/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \
+ $(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \
+ $(cmd_ld_single)) \
+ $(cmd_objtool)
define rule_rustc_o_rs
$(call cmd_and_fixdep,rustc_o_rs)
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index f9b545104f21..d5f9a0ca742c 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -10,8 +10,15 @@ import os
import pathlib
import subprocess
import sys
+from typing import Dict, Iterable, List, Literal, Optional, TypedDict
-def args_crates_cfgs(cfgs):
+def invoke_rustc(args: List[str]) -> str:
+ return subprocess.check_output(
+ [os.environ["RUSTC"]] + args,
+ stdin=subprocess.DEVNULL,
+ ).decode('utf-8').strip()
+
+def args_crates_cfgs(cfgs: List[str]) -> Dict[str, List[str]]:
crates_cfgs = {}
for cfg in cfgs:
crate, vals = cfg.split("=", 1)
@@ -19,54 +26,153 @@ def args_crates_cfgs(cfgs):
return crates_cfgs
-def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edition):
+class Dependency(TypedDict):
+ crate: int
+ name: str
+
+
+class Source(TypedDict):
+ include_dirs: List[str]
+ exclude_dirs: List[str]
+
+
+class Crate(TypedDict):
+ display_name: str
+ root_module: str
+ is_workspace_member: bool
+ deps: List[Dependency]
+ cfg: List[str]
+ edition: str
+ env: Dict[str, str]
+
+
+class ProcMacroCrate(Crate):
+ is_proc_macro: Literal[True]
+ proc_macro_dylib_path: str # `pathlib.Path` is not JSON serializable.
+
+
+class CrateWithGenerated(Crate):
+ source: Source
+
+
+def generate_crates(
+ srctree: pathlib.Path,
+ objtree: pathlib.Path,
+ sysroot_src: pathlib.Path,
+ external_src: Optional[pathlib.Path],
+ cfgs: List[str],
+ core_edition: str,
+) -> List[Crate]:
# Generate the configuration list.
- cfg = []
+ generated_cfg = []
with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
for line in fd:
line = line.replace("--cfg=", "")
line = line.replace("\n", "")
- cfg.append(line)
+ generated_cfg.append(line)
- # Now fill the crates list -- dependencies need to come first.
- #
- # Avoid O(n^2) iterations by keeping a map of indexes.
- crates = []
- crates_indexes = {}
+ # Now fill the crates list.
+ crates: List[Crate] = []
crates_cfgs = args_crates_cfgs(cfgs)
- def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
- crate = {
+ def get_crate_name(path: pathlib.Path) -> str:
+ return invoke_rustc(["--print", "crate-name", str(path)])
+
+ def build_crate(
+ display_name: str,
+ root_module: pathlib.Path,
+ deps: List[Dependency],
+ *,
+ cfg: Optional[List[str]],
+ is_workspace_member: Optional[bool],
+ edition: Optional[str],
+ ) -> Crate:
+ cfg = cfg if cfg is not None else crates_cfgs.get(display_name, [])
+ is_workspace_member = (
+ is_workspace_member if is_workspace_member is not None else True
+ )
+ edition = edition if edition is not None else "2021"
+ return {
"display_name": display_name,
"root_module": str(root_module),
"is_workspace_member": is_workspace_member,
- "is_proc_macro": is_proc_macro,
- "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps],
+ "deps": deps,
"cfg": cfg,
"edition": edition,
"env": {
"RUST_MODFILE": "This is only for rust-analyzer"
}
}
- if is_proc_macro:
- proc_macro_dylib_name = subprocess.check_output(
- [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"],
- stdin=subprocess.DEVNULL,
- ).decode('utf-8').strip()
- crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}"
- crates_indexes[display_name] = len(crates)
+
+ def append_proc_macro_crate(
+ display_name: str,
+ root_module: pathlib.Path,
+ deps: List[Dependency],
+ *,
+ cfg: Optional[List[str]] = None,
+ is_workspace_member: Optional[bool] = None,
+ edition: Optional[str] = None,
+ ) -> Dependency:
+ crate = build_crate(
+ display_name,
+ root_module,
+ deps,
+ cfg=cfg,
+ is_workspace_member=is_workspace_member,
+ edition=edition,
+ )
+ proc_macro_dylib_name = invoke_rustc([
+ "--print",
+ "file-names",
+ "--crate-name",
+ display_name,
+ "--crate-type",
+ "proc-macro",
+ "-",
+ ])
+ proc_macro_crate: ProcMacroCrate = {
+ **crate,
+ "is_proc_macro": True,
+ "proc_macro_dylib_path": str(objtree / "rust" / proc_macro_dylib_name),
+ }
+ return register_crate(proc_macro_crate)
+
+ def register_crate(crate: Crate) -> Dependency:
+ index = len(crates)
crates.append(crate)
+ return {"crate": index, "name": crate["display_name"]}
+
+ def append_crate(
+ display_name: str,
+ root_module: pathlib.Path,
+ deps: List[Dependency],
+ *,
+ cfg: Optional[List[str]] = None,
+ is_workspace_member: Optional[bool] = None,
+ edition: Optional[str] = None,
+ ) -> Dependency:
+ return register_crate(
+ build_crate(
+ display_name,
+ root_module,
+ deps,
+ cfg=cfg,
+ is_workspace_member=is_workspace_member,
+ edition=edition,
+ )
+ )
def append_sysroot_crate(
- display_name,
- deps,
- cfg=[],
- ):
- append_crate(
+ display_name: str,
+ deps: List[Dependency],
+ *,
+ cfg: Optional[List[str]] = None,
+ ) -> Dependency:
+ return append_crate(
display_name,
sysroot_src / display_name / "src" / "lib.rs",
deps,
- cfg,
+ cfg=cfg,
is_workspace_member=False,
# Miguel Ojeda writes:
#
@@ -98,129 +204,146 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit
# NB: sysroot crates reexport items from one another so setting up our transitive dependencies
# here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth
# for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`.
- append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", []))
- append_sysroot_crate("alloc", ["core"])
- append_sysroot_crate("std", ["alloc", "core"])
- append_sysroot_crate("proc_macro", ["core", "std"])
+ core = append_sysroot_crate("core", [])
+ alloc = append_sysroot_crate("alloc", [core])
+ std = append_sysroot_crate("std", [alloc, core])
+ proc_macro = append_sysroot_crate("proc_macro", [core, std])
- append_crate(
+ compiler_builtins = append_crate(
"compiler_builtins",
srctree / "rust" / "compiler_builtins.rs",
- ["core"],
+ [core],
)
- append_crate(
+ proc_macro2 = append_crate(
"proc_macro2",
srctree / "rust" / "proc-macro2" / "lib.rs",
- ["core", "alloc", "std", "proc_macro"],
- cfg=crates_cfgs["proc_macro2"],
+ [core, alloc, std, proc_macro],
)
- append_crate(
+ quote = append_crate(
"quote",
srctree / "rust" / "quote" / "lib.rs",
- ["core", "alloc", "std", "proc_macro", "proc_macro2"],
- cfg=crates_cfgs["quote"],
+ [core, alloc, std, proc_macro, proc_macro2],
edition="2018",
)
- append_crate(
+ syn = append_crate(
"syn",
srctree / "rust" / "syn" / "lib.rs",
- ["std", "proc_macro", "proc_macro2", "quote"],
- cfg=crates_cfgs["syn"],
+ [std, proc_macro, proc_macro2, quote],
)
- append_crate(
+ macros = append_proc_macro_crate(
"macros",
srctree / "rust" / "macros" / "lib.rs",
- ["std", "proc_macro", "proc_macro2", "quote", "syn"],
- is_proc_macro=True,
+ [std, proc_macro, proc_macro2, quote, syn],
)
- append_crate(
+ build_error = append_crate(
"build_error",
srctree / "rust" / "build_error.rs",
- ["core", "compiler_builtins"],
+ [core, compiler_builtins],
)
- append_crate(
+ pin_init_internal = append_proc_macro_crate(
"pin_init_internal",
srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs",
- ["std", "proc_macro", "proc_macro2", "quote", "syn"],
- cfg=["kernel"],
- is_proc_macro=True,
+ [std, proc_macro, proc_macro2, quote, syn],
)
- append_crate(
+ pin_init = append_crate(
"pin_init",
srctree / "rust" / "pin-init" / "src" / "lib.rs",
- ["core", "compiler_builtins", "pin_init_internal", "macros"],
- cfg=["kernel"],
+ [core, compiler_builtins, pin_init_internal, macros],
)
- append_crate(
+ ffi = append_crate(
"ffi",
srctree / "rust" / "ffi.rs",
- ["core", "compiler_builtins"],
+ [core, compiler_builtins],
)
def append_crate_with_generated(
- display_name,
- deps,
- ):
- append_crate(
+ display_name: str,
+ deps: List[Dependency],
+ ) -> Dependency:
+ crate = build_crate(
display_name,
srctree / "rust"/ display_name / "lib.rs",
deps,
- cfg=cfg,
+ cfg=generated_cfg,
+ is_workspace_member=True,
+ edition=None,
)
- crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
- crates[-1]["source"] = {
- "include_dirs": [
- str(srctree / "rust" / display_name),
- str(objtree / "rust")
- ],
- "exclude_dirs": [],
+ crate["env"]["OBJTREE"] = str(objtree.resolve(True))
+ crate_with_generated: CrateWithGenerated = {
+ **crate,
+ "source": {
+ "include_dirs": [
+ str(srctree / "rust" / display_name),
+ str(objtree / "rust"),
+ ],
+ "exclude_dirs": [],
+ },
}
+ return register_crate(crate_with_generated)
+
+ bindings = append_crate_with_generated("bindings", [core, ffi, pin_init])
+ uapi = append_crate_with_generated("uapi", [core, ffi, pin_init])
+ kernel = append_crate_with_generated(
+ "kernel", [core, macros, build_error, pin_init, ffi, bindings, uapi]
+ )
- append_crate_with_generated("bindings", ["core", "ffi", "pin_init"])
- append_crate_with_generated("uapi", ["core", "ffi", "pin_init"])
- append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"])
+ scripts = srctree / "scripts"
+ makefile = (scripts / "Makefile").read_text()
+ for path in scripts.glob("*.rs"):
+ name = path.stem
+ if f"{name}-rust" not in makefile:
+ continue
+ append_crate(
+ name,
+ path,
+ [std],
+ )
- def is_root_crate(build_file, target):
+ def is_root_crate(build_file: pathlib.Path, target: str) -> bool:
try:
- return f"{target}.o" in open(build_file).read()
+ contents = build_file.read_text()
except FileNotFoundError:
return False
+ return f"{target}.o" in contents
# Then, the rest outside of `rust/`.
#
# We explicitly mention the top-level folders we want to cover.
- extra_dirs = map(lambda dir: srctree / dir, ("samples", "drivers"))
+ extra_dirs: Iterable[pathlib.Path] = (
+ srctree / dir for dir in ("samples", "drivers")
+ )
if external_src is not None:
extra_dirs = [external_src]
for folder in extra_dirs:
for path in folder.rglob("*.rs"):
logging.info("Checking %s", path)
- name = path.name.replace(".rs", "")
+ file_name = path.stem
# Skip those that are not crate roots.
- if not is_root_crate(path.parent / "Makefile", name) and \
- not is_root_crate(path.parent / "Kbuild", name):
+ if not is_root_crate(path.parent / "Makefile", file_name) and \
+ not is_root_crate(path.parent / "Kbuild", file_name):
continue
- logging.info("Adding %s", name)
+ crate_name = get_crate_name(path)
+ logging.info("Adding %s", crate_name)
append_crate(
- name,
+ crate_name,
path,
- ["core", "kernel", "pin_init"],
- cfg=cfg,
+ [core, kernel, pin_init],
+ cfg=generated_cfg,
)
return crates
-def main():
+def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', '-v', action='store_true')
parser.add_argument('--cfgs', action='append', default=[])
@@ -230,7 +353,18 @@ def main():
parser.add_argument("sysroot", type=pathlib.Path)
parser.add_argument("sysroot_src", type=pathlib.Path)
parser.add_argument("exttree", type=pathlib.Path, nargs="?")
- args = parser.parse_args()
+
+ class Args(argparse.Namespace):
+ verbose: bool
+ cfgs: List[str]
+ srctree: pathlib.Path
+ objtree: pathlib.Path
+ sysroot: pathlib.Path
+ sysroot_src: pathlib.Path
+ exttree: Optional[pathlib.Path]
+ core_edition: str
+
+ args = parser.parse_args(namespace=Args())
logging.basicConfig(
format="[%(asctime)s] [%(levelname)s] %(message)s",
diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh
index 99b5575c1ef7..b96ec2d379b6 100755
--- a/scripts/min-tool-version.sh
+++ b/scripts/min-tool-version.sh
@@ -31,10 +31,10 @@ llvm)
fi
;;
rustc)
- echo 1.78.0
+ echo 1.85.0
;;
bindgen)
- echo 0.65.1
+ echo 0.71.1
;;
*)
echo "$1: unknown tool" >&2
diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh
index d2323de0692c..551f1ebd0dcb 100755
--- a/scripts/rust_is_available.sh
+++ b/scripts/rust_is_available.sh
@@ -121,14 +121,8 @@ fi
# Check that the Rust bindings generator is suitable.
#
# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
-#
-# The dummy parameter `workaround-for-0.69.0` is required to support 0.69.0
-# (https://github.com/rust-lang/rust-bindgen/pull/2678) and 0.71.0
-# (https://github.com/rust-lang/rust-bindgen/pull/3040). It can be removed when
-# the minimum version is upgraded past the latter (0.69.1 and 0.71.1 both fixed
-# the issue).
rust_bindings_generator_output=$( \
- LC_ALL=C "$BINDGEN" --version workaround-for-0.69.0 2>/dev/null
+ LC_ALL=C "$BINDGEN" --version 2>/dev/null
) || rust_bindings_generator_code=$?
if [ -n "$rust_bindings_generator_code" ]; then
echo >&2 "***"
@@ -163,19 +157,6 @@ if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cvers
echo >&2 "***"
exit 1
fi
-if [ "$rust_bindings_generator_cversion" -eq 6600 ] ||
- [ "$rust_bindings_generator_cversion" -eq 6601 ]; then
- # Distributions may have patched the issue (e.g. Debian did).
- if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_0_66.h >/dev/null; then
- echo >&2 "***"
- echo >&2 "*** Rust bindings generator '$BINDGEN' versions 0.66.0 and 0.66.1 may not"
- echo >&2 "*** work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2567),"
- echo >&2 "*** unless patched (like Debian's)."
- echo >&2 "*** Your version: $rust_bindings_generator_version"
- echo >&2 "***"
- warning=1
- fi
-fi
# Check that the `libclang` used by the Rust bindings generator is suitable.
#
@@ -227,21 +208,6 @@ if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then
exit 1
fi
-if [ "$bindgen_libclang_cversion" -ge 1900100 ] &&
- [ "$rust_bindings_generator_cversion" -lt 6905 ]; then
- # Distributions may have patched the issue (e.g. Debian did).
- if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang_concat.h | grep -q foofoo; then
- echo >&2 "***"
- echo >&2 "*** Rust bindings generator '$BINDGEN' < 0.69.5 together with libclang >= 19.1"
- echo >&2 "*** may not work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2824),"
- echo >&2 "*** unless patched (like Debian's)."
- echo >&2 "*** Your bindgen version: $rust_bindings_generator_version"
- echo >&2 "*** Your libclang version: $bindgen_libclang_version"
- echo >&2 "***"
- warning=1
- fi
-fi
-
# If the C compiler is Clang, then we can also check whether its version
# matches the `libclang` version used by the Rust bindings generator.
#
diff --git a/scripts/rust_is_available_bindgen_0_66.h b/scripts/rust_is_available_bindgen_0_66.h
deleted file mode 100644
index c0431293421c..000000000000
--- a/scripts/rust_is_available_bindgen_0_66.h
+++ /dev/null
@@ -1,2 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#define A "\0"
diff --git a/scripts/rust_is_available_bindgen_libclang_concat.h b/scripts/rust_is_available_bindgen_libclang_concat.h
deleted file mode 100644
index efc6e98d0f1d..000000000000
--- a/scripts/rust_is_available_bindgen_libclang_concat.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#define F(x) int x##x
-F(foo);
diff --git a/scripts/rust_is_available_test.py b/scripts/rust_is_available_test.py
index 4fcc319dea84..d6d54b7ea42a 100755
--- a/scripts/rust_is_available_test.py
+++ b/scripts/rust_is_available_test.py
@@ -54,37 +54,23 @@ else:
""")
@classmethod
- def generate_bindgen(cls, version_stdout, libclang_stderr, version_0_66_patched=False, libclang_concat_patched=False):
+ def generate_bindgen(cls, version_stdout, libclang_stderr):
if libclang_stderr is None:
libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})"
else:
libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)"
- if version_0_66_patched:
- version_0_66_case = "pass"
- else:
- version_0_66_case = "raise SystemExit(1)"
-
- if libclang_concat_patched:
- libclang_concat_case = "print('pub static mut foofoo: ::std::os::raw::c_int;')"
- else:
- libclang_concat_case = "pass"
-
return cls.generate_executable(f"""#!/usr/bin/env python3
import sys
if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv):
{libclang_case}
-elif "rust_is_available_bindgen_0_66.h" in " ".join(sys.argv):
- {version_0_66_case}
-elif "rust_is_available_bindgen_libclang_concat.h" in " ".join(sys.argv):
- {libclang_concat_case}
else:
print({repr(version_stdout)})
""")
@classmethod
- def generate_bindgen_version(cls, stdout, version_0_66_patched=False):
- return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr, version_0_66_patched)
+ def generate_bindgen_version(cls, stdout):
+ return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr)
@classmethod
def generate_bindgen_libclang_failure(cls):
@@ -245,19 +231,6 @@ else:
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
self.assertIn(f"Rust bindings generator '{bindgen}' is too old.", result.stderr)
- def test_bindgen_bad_version_0_66_0_and_0_66_1(self):
- for version in ("0.66.0", "0.66.1"):
- with self.subTest(version=version):
- bindgen = self.generate_bindgen_version(f"bindgen {version}")
- result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen })
- self.assertIn(f"Rust bindings generator '{bindgen}' versions 0.66.0 and 0.66.1 may not", result.stderr)
-
- def test_bindgen_bad_version_0_66_0_and_0_66_1_patched(self):
- for version in ("0.66.0", "0.66.1"):
- with self.subTest(version=version):
- bindgen = self.generate_bindgen_version(f"bindgen {version}", True)
- result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen })
-
def test_bindgen_libclang_failure(self):
bindgen = self.generate_bindgen_libclang_failure()
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
@@ -275,31 +248,6 @@ else:
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr)
- def test_bindgen_bad_libclang_concat(self):
- for (bindgen_version, libclang_version, expected_not_patched) in (
- ("0.69.4", "18.0.0", self.Expected.SUCCESS),
- ("0.69.4", "19.1.0", self.Expected.SUCCESS_WITH_WARNINGS),
- ("0.69.4", "19.2.0", self.Expected.SUCCESS_WITH_WARNINGS),
-
- ("0.69.5", "18.0.0", self.Expected.SUCCESS),
- ("0.69.5", "19.1.0", self.Expected.SUCCESS),
- ("0.69.5", "19.2.0", self.Expected.SUCCESS),
-
- ("0.70.0", "18.0.0", self.Expected.SUCCESS),
- ("0.70.0", "19.1.0", self.Expected.SUCCESS),
- ("0.70.0", "19.2.0", self.Expected.SUCCESS),
- ):
- with self.subTest(bindgen_version=bindgen_version, libclang_version=libclang_version):
- cc = self.generate_clang(f"clang version {libclang_version}")
- libclang_stderr = f"scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version {libclang_version} [-W#pragma-messages], err: false"
- bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr)
- result = self.run_script(expected_not_patched, { "BINDGEN": bindgen, "CC": cc })
- if expected_not_patched == self.Expected.SUCCESS_WITH_WARNINGS:
- self.assertIn(f"Rust bindings generator '{bindgen}' < 0.69.5 together with libclang >= 19.1", result.stderr)
-
- bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr, libclang_concat_patched=True)
- result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen, "CC": cc })
-
def test_clang_matches_bindgen_libclang_different_bindgen(self):
bindgen = self.generate_bindgen_libclang("scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version 999.0.0 [-W#pragma-messages], err: false")
result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen })