Merge 26ff969926 ("Merge tag 'rust-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux") into android-mainline
Steps on the way to v7.1-rc1 Change-Id: I6a00b3a1e58f5f308183202eb7fd54506a8eb662 Signed-off-by: Carlos Llamas <cmllamas@google.com>
This commit is contained in:
commit
c752154b9b
78 files changed
+1396
-826
No files matched your search
+11
-1
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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``).
|
||||
@@ -23173,6 +23173,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/
|
||||
|
||||
@@ -505,6 +505,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 \
|
||||
@@ -513,6 +514,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 \
|
||||
@@ -523,7 +525,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))
|
||||
@@ -534,6 +536,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)
|
||||
@@ -647,7 +650,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
|
||||
@@ -854,6 +857,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
|
||||
|
||||
+1
-2
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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,
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
|
||||
@@ -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)?;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+16
-14
@@ -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
|
||||
|
||||
@@ -2188,9 +2197,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.
|
||||
|
||||
@@ -2214,12 +2221,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
|
||||
|
||||
@@ -3583,6 +3583,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
|
||||
+36
-33
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -155,7 +155,6 @@ 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
|
||||
|
||||
#ifdef CONFIG_ASHMEM_RUST
|
||||
|
||||
@@ -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)]
|
||||
|
||||
+4
-1
@@ -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);
|
||||
|
||||
+13
-11
@@ -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);
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
+158
-35
@@ -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.
|
||||
///
|
||||
/// # 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
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// 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
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// 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
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`static_assert!`]: crate::static_assert!
|
||||
/// 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
|
||||
///
|
||||
/// ```
|
||||
/// #[inline(always)] // Important.
|
||||
/// fn bar(n: usize) {
|
||||
/// build_assert!(n > 1);
|
||||
/// }
|
||||
///
|
||||
/// fn foo() {
|
||||
/// bar(2);
|
||||
/// }
|
||||
///
|
||||
/// #[inline(always)] // Important.
|
||||
/// const fn const_bar(n: usize) {
|
||||
/// build_assert!(n > 1);
|
||||
/// }
|
||||
///
|
||||
/// const _: () = const_bar(2);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! build_assert {
|
||||
($cond:expr $(,)?) => {{
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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();
|
||||
|
||||
+6
-7
@@ -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()) };
|
||||
|
||||
+2
-36
@@ -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;
|
||||
|
||||
+19
-3
@@ -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.
|
||||
///
|
||||
|
||||
+2
-21
@@ -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
|
||||
|
||||
@@ -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)*
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
+82
-28
@@ -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;
|
||||
+35
-7
@@ -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,
|
||||
}
|
||||
}
|
||||
+128
-44
@@ -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;
|
||||
//! ```
|
||||
|
||||
/// 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;
|
||||
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,)*);
|
||||
};
|
||||
}
|
||||
|
||||
define_sizes!(u32, u64, usize);
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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)?);
|
||||
};
|
||||
}
|
||||
+23
-4
@@ -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.
|
||||
|
||||
+2
-19
@@ -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
|
||||
|
||||
+3
-4
@@ -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.
|
||||
|
||||
+26
-6
@@ -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.
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-4
@@ -18,10 +18,8 @@ use crate::{
|
||||
to_result, //
|
||||
},
|
||||
prelude::*,
|
||||
types::{
|
||||
AlwaysRefCounted,
|
||||
Opaque, //
|
||||
},
|
||||
sync::aref::AlwaysRefCounted,
|
||||
types::Opaque,
|
||||
ThisModule, //
|
||||
};
|
||||
use core::{
|
||||
|
||||
@@ -172,6 +172,7 @@ pub struct StoreError<T> {
|
||||
}
|
||||
|
||||
impl<T> From<StoreError<T>> for Error {
|
||||
#[inline]
|
||||
fn from(value: StoreError<T>) -> Self {
|
||||
value.error
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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::{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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::{
|
||||
|
||||
@@ -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
|
||||
)
|
||||
};
|
||||
});
|
||||
|
||||
@@ -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)]
|
||||
|
||||
|
||||
+50
-23
@@ -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).
|
||||
///
|
||||
|
||||
+1
-4
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
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"])
|
||||
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]
|
||||
)
|
||||
|
||||
def is_root_crate(build_file, target):
|
||||
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: 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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
#
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#define A "\0"
|
||||
@@ -1,3 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#define F(x) int x##x
|
||||
F(foo);
|
||||
@@ -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 })
|
||||
|
||||
Reference in new issue
Block a user