Merge tag 'rust-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux

Pull Rust updates from Miguel Ojeda:
 "Toolchain and infrastructure:

   - Extract the 'pin-init' API from the 'kernel' crate and make it into
     a standalone crate.

     In order to do this, the contents are rearranged so that they can
     easily be kept in sync with the version maintained out-of-tree that
     other projects have started to use too (or plan to, like QEMU).

     This will reduce the maintenance burden for Benno, who will now
     have his own sub-tree, and will simplify future expected changes
     like the move to use 'syn' to simplify the implementation.

   - Add '#[test]'-like support based on KUnit.

     We already had doctests support based on KUnit, which takes the
     examples in our Rust documentation and runs them under KUnit.

     Now, we are adding the beginning of the support for "normal" tests,
     similar to those the '#[test]' tests in userspace Rust. For
     instance:

         #[kunit_tests(my_suite)]
         mod tests {
             #[test]
             fn my_test() {
                 assert_eq!(1 + 1, 2);
             }
         }

     Unlike with doctests, the 'assert*!'s do not map to the KUnit
     assertion APIs yet.

   - Check Rust signatures at compile time for functions called from C
     by name.

     In particular, introduce a new '#[export]' macro that can be placed
     in the Rust function definition. It will ensure that the function
     declaration on the C side matches the signature on the Rust
     function:

         #[export]
         pub unsafe extern "C" fn my_function(a: u8, b: i32) -> usize {
             // ...
         }

     The macro essentially forces the compiler to compare the types of
     the actual Rust function and the 'bindgen'-processed C signature.

     These cases are rare so far. In the future, we may consider
     introducing another tool, 'cbindgen', to generate C headers
     automatically. Even then, having these functions explicitly marked
     may be a good idea anyway.

   - Enable the 'raw_ref_op' Rust feature: it is already stable, and
     allows us to use the new '&raw' syntax, avoiding a couple macros.
     After everyone has migrated, we will disallow the macros.

   - Pass the correct target to 'bindgen' on Usermode Linux.

   - Fix 'rusttest' build in macOS.

  'kernel' crate:

   - New 'hrtimer' module: add support for setting up intrusive timers
     without allocating when starting the timer. Add support for
     'Pin<Box<_>>', 'Arc<_>', 'Pin<&_>' and 'Pin<&mut _>' as pointer
     types for use with timer callbacks. Add support for setting clock
     source and timer mode.

   - New 'dma' module: add a simple DMA coherent allocator abstraction
     and a test sample driver.

   - 'list' module: make the linked list 'Cursor' point between
     elements, rather than at an element, which is more convenient to us
     and allows for cursors to empty lists; and document it with
     examples of how to perform common operations with the provided
     methods.

   - 'str' module: implement a few traits for 'BStr' as well as the
     'strip_prefix()' method.

   - 'sync' module: add 'Arc::as_ptr'.

   - 'alloc' module: add 'Box::into_pin'.

   - 'error' module: extend the 'Result' documentation, including a few
     examples on different ways of handling errors, a warning about
     using methods that may panic, and links to external documentation.

  'macros' crate:

   - 'module' macro: add the 'authors' key to support multiple authors.
     The original key will be kept until everyone has migrated.

  Documentation:

   - Add error handling sections.

  MAINTAINERS:

   - Add Danilo Krummrich as reviewer of the Rust "subsystem".

   - Add 'RUST [PIN-INIT]' entry with Benno Lossin as maintainer. It has
     its own sub-tree.

   - Add sub-tree for 'RUST [ALLOC]'.

   - Add 'DMA MAPPING HELPERS DEVICE DRIVER API [RUST]' entry with
     Abdiel Janulgue as primary maintainer. It will go through the
     sub-tree of the 'RUST [ALLOC]' entry.

   - Add 'HIGH-RESOLUTION TIMERS [RUST]' entry with Andreas Hindborg as
     maintainer. It has its own sub-tree.

  And a few other cleanups and improvements"

* tag 'rust-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (71 commits)
  rust: dma: add `Send` implementation for `CoherentAllocation`
  rust: macros: fix `make rusttest` build on macOS
  rust: block: refactor to use `&raw mut`
  rust: enable `raw_ref_op` feature
  rust: uaccess: name the correct function
  rust: rbtree: fix comments referring to Box instead of KBox
  rust: hrtimer: add maintainer entry
  rust: hrtimer: add clocksource selection through `ClockId`
  rust: hrtimer: add `HrTimerMode`
  rust: hrtimer: implement `HrTimerPointer` for `Pin<Box<T>>`
  rust: alloc: add `Box::into_pin`
  rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&mut T>`
  rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&T>`
  rust: hrtimer: add `hrtimer::ScopedHrTimerPointer`
  rust: hrtimer: add `UnsafeHrTimerPointer`
  rust: hrtimer: allow timer restart from timer handler
  rust: str: implement `strip_prefix` for `BStr`
  rust: str: implement `AsRef<BStr>` for `[u8]` and `BStr`
  rust: str: implement `Index` for `BStr`
  rust: str: implement `PartialEq` for `BStr`
  ...
This commit is contained in:
Linus Torvalds
2025-03-30 17:03:26 -07:00
85 changed files with 6008 additions and 1854 deletions

View File

@@ -373,3 +373,11 @@ triggered due to non-local changes (such as ``dead_code``).
For more information about diagnostics in Rust, please see:
https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html
Error handling
--------------
For some background and guidelines about Rust for Linux specific error handling,
please see:
https://rust.docs.kernel.org/kernel/error/type.Result.html#error-codes-in-c-and-rust

View File

@@ -123,6 +123,13 @@ A current limitation is that KUnit does not support assertions in other tasks.
Thus, we presently simply print an error to the kernel log if an assertion
actually failed. Additionally, doctests are not run for nonpublic functions.
Since these tests are examples, i.e. they are part of the documentation, they
should generally be written like "real code". Thus, for example, instead of
using ``unwrap()`` or ``expect()``, use the ``?`` operator. For more background,
please see:
https://rust.docs.kernel.org/kernel/error/type.Result.html#error-codes-in-c-and-rust
The ``#[test]`` tests
---------------------

View File

@@ -6981,6 +6981,19 @@ F: include/linux/dma-mapping.h
F: include/linux/swiotlb.h
F: kernel/dma/
DMA MAPPING HELPERS DEVICE DRIVER API [RUST]
M: Abdiel Janulgue <abdiel.janulgue@gmail.com>
M: Danilo Krummrich <dakr@kernel.org>
R: Daniel Almeida <daniel.almeida@collabora.com>
R: Robin Murphy <robin.murphy@arm.com>
R: Andreas Hindborg <a.hindborg@kernel.org>
L: rust-for-linux@vger.kernel.org
S: Supported
W: https://rust-for-linux.com
T: git https://github.com/Rust-for-Linux/linux.git alloc-next
F: rust/kernel/dma.rs
F: samples/rust/rust_dma.rs
DMA-BUF HEAPS FRAMEWORK
M: Sumit Semwal <sumit.semwal@linaro.org>
R: Benjamin Gaignard <benjamin.gaignard@collabora.com>
@@ -10539,6 +10552,21 @@ F: kernel/time/timer_list.c
F: kernel/time/timer_migration.*
F: tools/testing/selftests/timers/
HIGH-RESOLUTION TIMERS [RUST]
M: Andreas Hindborg <a.hindborg@kernel.org>
R: Boqun Feng <boqun.feng@gmail.com>
R: Frederic Weisbecker <frederic@kernel.org>
R: Lyude Paul <lyude@redhat.com>
R: Thomas Gleixner <tglx@linutronix.de>
R: Anna-Maria Behnsen <anna-maria@linutronix.de>
L: rust-for-linux@vger.kernel.org
S: Supported
W: https://rust-for-linux.com
B: https://github.com/Rust-for-Linux/linux/issues
T: git https://github.com/Rust-for-Linux/linux.git hrtimer-next
F: rust/kernel/time/hrtimer.rs
F: rust/kernel/time/hrtimer/
HIGH-SPEED SCC DRIVER FOR AX.25
L: linux-hams@vger.kernel.org
S: Orphan
@@ -12902,6 +12930,7 @@ F: Documentation/dev-tools/kunit/
F: include/kunit/
F: lib/kunit/
F: rust/kernel/kunit.rs
F: rust/macros/kunit.rs
F: scripts/rustdoc_test_*
F: tools/testing/kunit/
@@ -20993,6 +21022,7 @@ R: Benno Lossin <benno.lossin@proton.me>
R: Andreas Hindborg <a.hindborg@kernel.org>
R: Alice Ryhl <aliceryhl@google.com>
R: Trevor Gross <tmgross@umich.edu>
R: Danilo Krummrich <dakr@kernel.org>
L: rust-for-linux@vger.kernel.org
S: Supported
W: https://rust-for-linux.com
@@ -21013,9 +21043,23 @@ RUST [ALLOC]
M: Danilo Krummrich <dakr@kernel.org>
L: rust-for-linux@vger.kernel.org
S: Maintained
T: git https://github.com/Rust-for-Linux/linux.git alloc-next
F: rust/kernel/alloc.rs
F: rust/kernel/alloc/
RUST [PIN-INIT]
M: Benno Lossin <benno.lossin@proton.me>
L: rust-for-linux@vger.kernel.org
S: Maintained
W: https://rust-for-linux.com/pin-init
B: https://github.com/Rust-for-Linux/pin-init/issues
C: zulip://rust-for-linux.zulipchat.com
P: rust/pin-init/CONTRIBUTING.md
T: git https://github.com/Rust-for-Linux/linux.git pin-init-next
F: rust/kernel/init.rs
F: rust/pin-init/
K: \bpin-init\b|pin_init\b|PinInit
RXRPC SOCKETS (AF_RXRPC)
M: David Howells <dhowells@redhat.com>
M: Marc Dionne <marc.dionne@auristor.com>

View File

@@ -27,7 +27,7 @@ use kernel::{
module! {
type: NullBlkModule,
name: "rnull_mod",
author: "Andreas Hindborg",
authors: ["Andreas Hindborg"],
description: "Rust implementation of the C null block driver",
license: "GPL v2",
}

View File

@@ -486,11 +486,6 @@ static void drm_panic_qr_exit(void)
stream.workspace = NULL;
}
extern size_t drm_panic_qr_max_data_size(u8 version, size_t url_len);
extern u8 drm_panic_qr_generate(const char *url, u8 *data, size_t data_len, size_t data_size,
u8 *tmp, size_t tmp_size);
static int drm_panic_get_qr_code_url(u8 **qr_image)
{
struct kmsg_dump_iter iter;

View File

@@ -27,7 +27,7 @@
//! * <https://github.com/erwanvivien/fast_qr>
//! * <https://github.com/bjguillot/qr>
use kernel::str::CStr;
use kernel::{prelude::*, str::CStr};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
struct Version(usize);
@@ -891,7 +891,7 @@ impl QrImage<'_> {
/// * `tmp` must be valid for reading and writing for `tmp_size` bytes.
///
/// They must remain valid for the duration of the function call.
#[no_mangle]
#[export]
pub unsafe extern "C" fn drm_panic_qr_generate(
url: *const kernel::ffi::c_char,
data: *mut u8,
@@ -942,8 +942,13 @@ pub unsafe extern "C" fn drm_panic_qr_generate(
/// * If `url_len` > 0, remove the 2 segments header/length and also count the
/// conversion to numeric segments.
/// * If `url_len` = 0, only removes 3 bytes for 1 binary segment.
#[no_mangle]
pub extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {
///
/// # Safety
///
/// Always safe to call.
// Required to be unsafe due to the `#[export]` annotation.
#[export]
pub unsafe extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {
#[expect(clippy::manual_range_contains)]
if version < 1 || version > 40 {
return 0;

View File

@@ -19,7 +19,7 @@ kernel::module_phy_driver! {
DeviceId::new_with_driver::<PhyAX88796B>()
],
name: "rust_asix_phy",
author: "FUJITA Tomonori <fujita.tomonori@gmail.com>",
authors: ["FUJITA Tomonori <fujita.tomonori@gmail.com>"],
description: "Rust Asix PHYs driver",
license: "GPL",
}

View File

@@ -26,7 +26,7 @@ kernel::module_phy_driver! {
phy::DeviceId::new_with_driver::<PhyQT2025>(),
],
name: "qt2025_phy",
author: "FUJITA Tomonori <fujita.tomonori@gmail.com>",
authors: ["FUJITA Tomonori <fujita.tomonori@gmail.com>"],
description: "AMCC QT2025 PHY driver",
license: "GPL",
firmware: ["qt2025-2.0.3.3.fw"],

View File

@@ -163,4 +163,11 @@ static inline void drm_panic_unlock(struct drm_device *dev, unsigned long flags)
#endif
#if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
size_t drm_panic_qr_max_data_size(u8 version, size_t url_len);
u8 drm_panic_qr_generate(const char *url, u8 *data, size_t data_len, size_t data_size,
u8 *tmp, size_t tmp_size);
#endif
#endif /* __DRM_PANIC_H__ */

View File

@@ -24,4 +24,7 @@ __scanf(2, 0) int vsscanf(const char *, const char *, va_list);
extern bool no_hash_pointers;
int no_hash_pointers_enable(char *str);
/* Used for Rust formatting ('%pA') */
char *rust_fmt_argument(char *buf, char *end, const void *ptr);
#endif /* _LINUX_KERNEL_SPRINTF_H */

View File

@@ -2291,9 +2291,6 @@ int __init no_hash_pointers_enable(char *str)
}
early_param("no_hash_pointers", no_hash_pointers_enable);
/* Used for Rust formatting ('%pA'). */
char *rust_fmt_argument(char *buf, char *end, void *ptr);
/*
* Show a '%p' thing. A kernel extension is that the '%p' is followed
* by an extra set of alphanumeric characters that are extended format

3
rust/.kunitconfig Normal file
View File

@@ -0,0 +1,3 @@
CONFIG_KUNIT=y
CONFIG_RUST=y
CONFIG_RUST_KERNEL_DOCTESTS=y

View File

@@ -12,7 +12,7 @@ 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 kernel.o
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
@@ -41,7 +41,10 @@ ifdef CONFIG_RUST
libmacros_name := $(shell MAKEFLAGS= $(RUSTC) --print file-names --crate-name macros --crate-type proc-macro - </dev/null)
libmacros_extension := $(patsubst libmacros.%,%,$(libmacros_name))
always-$(CONFIG_RUST) += $(libmacros_name)
libpin_init_internal_name := $(shell MAKEFLAGS= $(RUSTC) --print file-names --crate-name pin_init_internal --crate-type proc-macro - </dev/null)
libpin_init_internal_extension := $(patsubst libpin_init_internal.%,%,$(libpin_init_internal_name))
always-$(CONFIG_RUST) += $(libmacros_name) $(libpin_init_internal_name)
# `$(rust_flags)` is passed in case the user added `--sysroot`.
rustc_sysroot := $(shell MAKEFLAGS= $(RUSTC) $(rust_flags) --print sysroot)
@@ -80,7 +83,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
# command-like flags to solve the issue. Meanwhile, we use the non-custom case
# and then retouch the generated files.
rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \
rustdoc-kernel
rustdoc-kernel rustdoc-pin_init
$(Q)cp $(srctree)/Documentation/images/logo.svg $(rustdoc_output)/static.files/
$(Q)cp $(srctree)/Documentation/images/COPYING-logo $(rustdoc_output)/static.files/
$(Q)find $(rustdoc_output) -name '*.html' -type f -print0 | xargs -0 sed -Ei \
@@ -110,11 +113,24 @@ rustdoc-compiler_builtins: $(src)/compiler_builtins.rs rustdoc-core FORCE
rustdoc-ffi: $(src)/ffi.rs rustdoc-core FORCE
+$(call if_changed,rustdoc)
rustdoc-kernel: private rustc_target_flags = --extern ffi \
rustdoc-pin_init_internal: private rustdoc_host = yes
rustdoc-pin_init_internal: private rustc_target_flags = --cfg kernel \
--extern proc_macro --crate-type proc-macro
rustdoc-pin_init_internal: $(src)/pin-init/internal/src/lib.rs FORCE
+$(call if_changed,rustdoc)
rustdoc-pin_init: private rustdoc_host = yes
rustdoc-pin_init: private rustc_target_flags = --extern pin_init_internal \
--extern macros --extern alloc --cfg kernel --cfg feature=\"alloc\"
rustdoc-pin_init: $(src)/pin-init/src/lib.rs rustdoc-pin_init_internal \
rustdoc-macros FORCE
+$(call if_changed,rustdoc)
rustdoc-kernel: private rustc_target_flags = --extern ffi --extern pin_init \
--extern build_error --extern macros \
--extern bindings --extern uapi
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-ffi rustdoc-macros \
rustdoc-compiler_builtins $(obj)/$(libmacros_name) \
rustdoc-pin_init rustdoc-compiler_builtins $(obj)/$(libmacros_name) \
$(obj)/bindings.o FORCE
+$(call if_changed,rustdoc)
@@ -139,12 +155,24 @@ rusttestlib-macros: private rustc_test_library_proc = yes
rusttestlib-macros: $(src)/macros/lib.rs FORCE
+$(call if_changed,rustc_test_library)
rusttestlib-pin_init_internal: private rustc_target_flags = --cfg kernel \
--extern proc_macro
rusttestlib-pin_init_internal: private rustc_test_library_proc = yes
rusttestlib-pin_init_internal: $(src)/pin-init/internal/src/lib.rs FORCE
+$(call if_changed,rustc_test_library)
rusttestlib-pin_init: private rustc_target_flags = --extern pin_init_internal \
--extern macros --cfg kernel
rusttestlib-pin_init: $(src)/pin-init/src/lib.rs rusttestlib-macros \
rusttestlib-pin_init_internal $(obj)/$(libpin_init_internal_name) FORCE
+$(call if_changed,rustc_test_library)
rusttestlib-kernel: private rustc_target_flags = --extern ffi \
--extern build_error --extern macros \
--extern build_error --extern macros --extern pin_init \
--extern bindings --extern uapi
rusttestlib-kernel: $(src)/kernel/lib.rs \
rusttestlib-bindings rusttestlib-uapi rusttestlib-build_error \
$(obj)/$(libmacros_name) $(obj)/bindings.o FORCE
rusttestlib-kernel: $(src)/kernel/lib.rs rusttestlib-bindings rusttestlib-uapi \
rusttestlib-build_error rusttestlib-pin_init $(obj)/$(libmacros_name) \
$(obj)/bindings.o FORCE
+$(call if_changed,rustc_test_library)
rusttestlib-bindings: private rustc_target_flags = --extern ffi
@@ -172,8 +200,8 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
OBJTREE=$(abspath $(objtree)) \
$(RUSTDOC) --test $(rust_flags) \
-L$(objtree)/$(obj) --extern ffi --extern kernel \
--extern build_error --extern macros \
-L$(objtree)/$(obj) --extern ffi --extern pin_init \
--extern kernel --extern build_error --extern macros \
--extern bindings --extern uapi \
--no-run --crate-name kernel -Zunstable-options \
--sysroot=/dev/null \
@@ -203,18 +231,18 @@ quiet_cmd_rustc_test = $(RUSTC_OR_CLIPPY_QUIET) T $<
rusttest: rusttest-macros rusttest-kernel
rusttest-macros: private rustc_target_flags = --extern proc_macro \
--extern macros --extern kernel
--extern macros --extern kernel --extern pin_init
rusttest-macros: private rustdoc_test_target_flags = --crate-type proc-macro
rusttest-macros: $(src)/macros/lib.rs \
rusttestlib-macros rusttestlib-kernel FORCE
rusttestlib-macros rusttestlib-kernel rusttestlib-pin_init FORCE
+$(call if_changed,rustc_test)
+$(call if_changed,rustdoc_test)
rusttest-kernel: private rustc_target_flags = --extern ffi \
rusttest-kernel: private rustc_target_flags = --extern ffi --extern pin_init \
--extern build_error --extern macros --extern bindings --extern uapi
rusttest-kernel: $(src)/kernel/lib.rs rusttestlib-ffi rusttestlib-kernel \
rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \
rusttestlib-uapi FORCE
rusttestlib-uapi rusttestlib-pin_init FORCE
+$(call if_changed,rustc_test)
ifdef CONFIG_CC_IS_CLANG
@@ -246,6 +274,7 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \
# Derived from `scripts/Makefile.clang`.
BINDGEN_TARGET_x86 := x86_64-linux-gnu
BINDGEN_TARGET_arm64 := aarch64-linux-gnu
BINDGEN_TARGET_um := $(BINDGEN_TARGET_$(SUBARCH))
BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH))
# All warnings are inhibited since GCC builds are very experimental,
@@ -361,7 +390,7 @@ $(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE
quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
cmd_rustc_procmacro = \
$(RUSTC_OR_CLIPPY) $(rust_common_flags) \
$(RUSTC_OR_CLIPPY) $(rust_common_flags) $(rustc_target_flags) \
-Clinker-flavor=gcc -Clinker=$(HOSTCC) \
-Clink-args='$(call escsq,$(KBUILD_PROCMACROLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
@@ -372,6 +401,10 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
$(obj)/$(libmacros_name): $(src)/macros/lib.rs FORCE
+$(call if_changed_dep,rustc_procmacro)
$(obj)/$(libpin_init_internal_name): private rustc_target_flags = --cfg kernel
$(obj)/$(libpin_init_internal_name): $(src)/pin-init/internal/src/lib.rs FORCE
+$(call if_changed_dep,rustc_procmacro)
quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@
cmd_rustc_library = \
OBJTREE=$(abspath $(objtree)) \
@@ -451,6 +484,13 @@ $(obj)/compiler_builtins.o: private rustc_objcopy = -w -W '__*'
$(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE
+$(call if_changed_rule,rustc_library)
$(obj)/pin_init.o: private skip_gendwarfksyms = 1
$(obj)/pin_init.o: private rustc_target_flags = --extern pin_init_internal \
--extern macros --cfg kernel
$(obj)/pin_init.o: $(src)/pin-init/src/lib.rs $(obj)/compiler_builtins.o \
$(obj)/$(libpin_init_internal_name) $(obj)/$(libmacros_name) FORCE
+$(call if_changed_rule,rustc_library)
$(obj)/build_error.o: private skip_gendwarfksyms = 1
$(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE
+$(call if_changed_rule,rustc_library)
@@ -473,9 +513,9 @@ $(obj)/uapi.o: $(src)/uapi/lib.rs \
$(obj)/uapi/uapi_generated.rs FORCE
+$(call if_changed_rule,rustc_library)
$(obj)/kernel.o: private rustc_target_flags = --extern ffi \
$(obj)/kernel.o: private rustc_target_flags = --extern ffi --extern pin_init \
--extern build_error --extern macros --extern bindings --extern uapi
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o \
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o $(obj)/pin_init.o \
$(obj)/$(libmacros_name) $(obj)/bindings.o $(obj)/uapi.o FORCE
+$(call if_changed_rule,rustc_library)

View File

@@ -13,6 +13,7 @@
#include <linux/cpumask.h>
#include <linux/cred.h>
#include <linux/device/faux.h>
#include <linux/dma-mapping.h>
#include <linux/errname.h>
#include <linux/ethtool.h>
#include <linux/file.h>
@@ -38,6 +39,11 @@
#include <linux/workqueue.h>
#include <trace/events/rust_sample.h>
#if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
// Used by `#[export]` in `drivers/gpu/drm/drm_panic_qr.rs`.
#include <drm/drm_panic.h>
#endif
/* `bindgen` gets confused at certain things. */
const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
const size_t RUST_CONST_HELPER_PAGE_SIZE = PAGE_SIZE;

View File

@@ -80,6 +80,7 @@ impl ReallocFunc {
/// This method has the same guarantees as `Allocator::realloc`. Additionally
/// - it accepts any pointer to a valid memory allocation allocated by this function.
/// - memory allocated by this function remains valid until it is passed to this function.
#[inline]
unsafe fn call(
&self,
ptr: Option<NonNull<u8>>,

View File

@@ -15,8 +15,9 @@ use core::pin::Pin;
use core::ptr::NonNull;
use core::result::Result;
use crate::init::{InPlaceInit, InPlaceWrite, Init, PinInit};
use crate::init::InPlaceInit;
use crate::types::ForeignOwnable;
use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption};
/// The kernel's [`Box`] type -- a heap allocation for a single value of type `T`.
///
@@ -99,6 +100,10 @@ pub type VBox<T> = Box<T, super::allocator::Vmalloc>;
/// ```
pub type KVBox<T> = Box<T, super::allocator::KVmalloc>;
// SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee:
// https://doc.rust-lang.org/stable/std/option/index.html#representation).
unsafe impl<T, A: Allocator> ZeroableOption for Box<T, A> {}
// SAFETY: `Box` is `Send` if `T` is `Send` because the `Box` owns a `T`.
unsafe impl<T, A> Send for Box<T, A>
where
@@ -245,6 +250,12 @@ where
Ok(Self::new(x, flags)?.into())
}
/// Convert a [`Box<T,A>`] to a [`Pin<Box<T,A>>`]. If `T` does not implement
/// [`Unpin`], then `x` will be pinned in memory and can't be moved.
pub fn into_pin(this: Self) -> Pin<Self> {
this.into()
}
/// Forgets the contents (does not run the destructor), but keeps the allocation.
fn forget_contents(this: Self) -> Box<MaybeUninit<T>, A> {
let ptr = Self::into_raw(this);

View File

@@ -12,7 +12,7 @@ use crate::{
};
use core::{
marker::PhantomData,
ptr::{addr_of_mut, NonNull},
ptr::NonNull,
sync::atomic::{AtomicU64, Ordering},
};
@@ -187,7 +187,7 @@ impl RequestDataWrapper {
pub(crate) unsafe fn refcount_ptr(this: *mut Self) -> *mut AtomicU64 {
// SAFETY: Because of the safety requirements of this function, the
// field projection is safe.
unsafe { addr_of_mut!((*this).refcount) }
unsafe { &raw mut (*this).refcount }
}
}

View File

@@ -10,12 +10,11 @@ use crate::{
bindings,
block::mq::{operations::OperationsVTable, request::RequestDataWrapper, Operations},
error,
prelude::PinInit,
try_pin_init,
prelude::try_pin_init,
types::Opaque,
};
use core::{convert::TryInto, marker::PhantomData};
use macros::{pin_data, pinned_drop};
use pin_init::{pin_data, pinned_drop, PinInit};
/// A wrapper for the C `struct blk_mq_tag_set`.
///

391
rust/kernel/dma.rs Normal file
View File

@@ -0,0 +1,391 @@
// SPDX-License-Identifier: GPL-2.0
//! Direct memory access (DMA).
//!
//! C header: [`include/linux/dma-mapping.h`](srctree/include/linux/dma-mapping.h)
use crate::{
bindings, build_assert,
device::Device,
error::code::*,
error::Result,
transmute::{AsBytes, FromBytes},
types::ARef,
};
/// Possible attributes associated with a DMA mapping.
///
/// They can be combined with the operators `|`, `&`, and `!`.
///
/// Values can be used from the [`attrs`] module.
///
/// # Examples
///
/// ```
/// use kernel::device::Device;
/// use kernel::dma::{attrs::*, CoherentAllocation};
///
/// # fn test(dev: &Device) -> Result {
/// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN;
/// let c: CoherentAllocation<u64> =
/// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, attribs)?;
/// # Ok::<(), Error>(()) }
/// ```
#[derive(Clone, Copy, PartialEq)]
#[repr(transparent)]
pub struct Attrs(u32);
impl Attrs {
/// Get the raw representation of this attribute.
pub(crate) fn as_raw(self) -> crate::ffi::c_ulong {
self.0 as _
}
/// Check whether `flags` is contained in `self`.
pub fn contains(self, flags: Attrs) -> bool {
(self & flags) == flags
}
}
impl core::ops::BitOr for Attrs {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl core::ops::BitAnd for Attrs {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
impl core::ops::Not for Attrs {
type Output = Self;
fn not(self) -> Self::Output {
Self(!self.0)
}
}
/// DMA mapping attributes.
pub mod attrs {
use super::Attrs;
/// Specifies that reads and writes to the mapping may be weakly ordered, that is that reads
/// and writes may pass each other.
pub const DMA_ATTR_WEAK_ORDERING: Attrs = Attrs(bindings::DMA_ATTR_WEAK_ORDERING);
/// Specifies that writes to the mapping may be buffered to improve performance.
pub const DMA_ATTR_WRITE_COMBINE: Attrs = Attrs(bindings::DMA_ATTR_WRITE_COMBINE);
/// Lets the platform to avoid creating a kernel virtual mapping for the allocated buffer.
pub const DMA_ATTR_NO_KERNEL_MAPPING: Attrs = Attrs(bindings::DMA_ATTR_NO_KERNEL_MAPPING);
/// Allows platform code to skip synchronization of the CPU cache for the given buffer assuming
/// that it has been already transferred to 'device' domain.
pub const DMA_ATTR_SKIP_CPU_SYNC: Attrs = Attrs(bindings::DMA_ATTR_SKIP_CPU_SYNC);
/// Forces contiguous allocation of the buffer in physical memory.
pub const DMA_ATTR_FORCE_CONTIGUOUS: Attrs = Attrs(bindings::DMA_ATTR_FORCE_CONTIGUOUS);
/// This is a hint to the DMA-mapping subsystem that it's probably not worth the time to try
/// to allocate memory to in a way that gives better TLB efficiency.
pub const DMA_ATTR_ALLOC_SINGLE_PAGES: Attrs = Attrs(bindings::DMA_ATTR_ALLOC_SINGLE_PAGES);
/// This tells the DMA-mapping subsystem to suppress allocation failure reports (similarly to
/// __GFP_NOWARN).
pub const DMA_ATTR_NO_WARN: Attrs = Attrs(bindings::DMA_ATTR_NO_WARN);
/// Used to indicate that the buffer is fully accessible at an elevated privilege level (and
/// ideally inaccessible or at least read-only at lesser-privileged levels).
pub const DMA_ATTR_PRIVILEGED: Attrs = Attrs(bindings::DMA_ATTR_PRIVILEGED);
}
/// An abstraction of the `dma_alloc_coherent` API.
///
/// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map
/// large consistent DMA regions.
///
/// A [`CoherentAllocation`] instance contains a pointer to the allocated region (in the
/// processor's virtual address space) and the device address which can be given to the device
/// as the DMA address base of the region. The region is released once [`CoherentAllocation`]
/// is dropped.
///
/// # Invariants
///
/// For the lifetime of an instance of [`CoherentAllocation`], the `cpu_addr` is a valid pointer
/// to an allocated region of consistent memory and `dma_handle` is the DMA address base of
/// the region.
// TODO
//
// DMA allocations potentially carry device resources (e.g.IOMMU mappings), hence for soundness
// reasons DMA allocation would need to be embedded in a `Devres` container, in order to ensure
// that device resources can never survive device unbind.
//
// However, it is neither desirable nor necessary to protect the allocated memory of the DMA
// allocation from surviving device unbind; it would require RCU read side critical sections to
// access the memory, which may require subsequent unnecessary copies.
//
// Hence, find a way to revoke the device resources of a `CoherentAllocation`, but not the
// entire `CoherentAllocation` including the allocated memory itself.
pub struct CoherentAllocation<T: AsBytes + FromBytes> {
dev: ARef<Device>,
dma_handle: bindings::dma_addr_t,
count: usize,
cpu_addr: *mut T,
dma_attrs: Attrs,
}
impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
/// Allocates a region of `size_of::<T> * count` of consistent memory.
///
/// # Examples
///
/// ```
/// use kernel::device::Device;
/// use kernel::dma::{attrs::*, CoherentAllocation};
///
/// # fn test(dev: &Device) -> Result {
/// let c: CoherentAllocation<u64> =
/// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
/// # Ok::<(), Error>(()) }
/// ```
pub fn alloc_attrs(
dev: &Device,
count: usize,
gfp_flags: kernel::alloc::Flags,
dma_attrs: Attrs,
) -> Result<CoherentAllocation<T>> {
build_assert!(
core::mem::size_of::<T>() > 0,
"It doesn't make sense for the allocated type to be a ZST"
);
let size = count
.checked_mul(core::mem::size_of::<T>())
.ok_or(EOVERFLOW)?;
let mut dma_handle = 0;
// SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
let ret = unsafe {
bindings::dma_alloc_attrs(
dev.as_raw(),
size,
&mut dma_handle,
gfp_flags.as_raw(),
dma_attrs.as_raw(),
)
};
if ret.is_null() {
return Err(ENOMEM);
}
// INVARIANT: We just successfully allocated a coherent region which is accessible for
// `count` elements, hence the cpu address is valid. We also hold a refcounted reference
// to the device.
Ok(Self {
dev: dev.into(),
dma_handle,
count,
cpu_addr: ret as *mut T,
dma_attrs,
})
}
/// Performs the same functionality as [`CoherentAllocation::alloc_attrs`], except the
/// `dma_attrs` is 0 by default.
pub fn alloc_coherent(
dev: &Device,
count: usize,
gfp_flags: kernel::alloc::Flags,
) -> Result<CoherentAllocation<T>> {
CoherentAllocation::alloc_attrs(dev, count, gfp_flags, Attrs(0))
}
/// Returns the base address to the allocated region in the CPU's virtual address space.
pub fn start_ptr(&self) -> *const T {
self.cpu_addr
}
/// Returns the base address to the allocated region in the CPU's virtual address space as
/// a mutable pointer.
pub fn start_ptr_mut(&mut self) -> *mut T {
self.cpu_addr
}
/// Returns a DMA handle which may given to the device as the DMA address base of
/// the region.
pub fn dma_handle(&self) -> bindings::dma_addr_t {
self.dma_handle
}
/// Returns a pointer to an element from the region with bounds checking. `offset` is in
/// units of `T`, not the number of bytes.
///
/// Public but hidden since it should only be used from [`dma_read`] and [`dma_write`] macros.
#[doc(hidden)]
pub fn item_from_index(&self, offset: usize) -> Result<*mut T> {
if offset >= self.count {
return Err(EINVAL);
}
// SAFETY:
// - The pointer is valid due to type invariant on `CoherentAllocation`
// and we've just checked that the range and index is within bounds.
// - `offset` can't overflow since it is smaller than `self.count` and we've checked
// that `self.count` won't overflow early in the constructor.
Ok(unsafe { self.cpu_addr.add(offset) })
}
/// Reads the value of `field` and ensures that its type is [`FromBytes`].
///
/// # Safety
///
/// This must be called from the [`dma_read`] macro which ensures that the `field` pointer is
/// validated beforehand.
///
/// Public but hidden since it should only be used from [`dma_read`] macro.
#[doc(hidden)]
pub unsafe fn field_read<F: FromBytes>(&self, field: *const F) -> F {
// SAFETY:
// - By the safety requirements field is valid.
// - Using read_volatile() here is not sound as per the usual rules, the usage here is
// a special exception with the following notes in place. When dealing with a potential
// race from a hardware or code outside kernel (e.g. user-space program), we need that
// read on a valid memory is not UB. Currently read_volatile() is used for this, and the
// rationale behind is that it should generate the same code as READ_ONCE() which the
// kernel already relies on to avoid UB on data races. Note that the usage of
// read_volatile() is limited to this particular case, it cannot be used to prevent
// the UB caused by racing between two kernel functions nor do they provide atomicity.
unsafe { field.read_volatile() }
}
/// Writes a value to `field` and ensures that its type is [`AsBytes`].
///
/// # Safety
///
/// This must be called from the [`dma_write`] macro which ensures that the `field` pointer is
/// validated beforehand.
///
/// Public but hidden since it should only be used from [`dma_write`] macro.
#[doc(hidden)]
pub unsafe fn field_write<F: AsBytes>(&self, field: *mut F, val: F) {
// SAFETY:
// - By the safety requirements field is valid.
// - Using write_volatile() here is not sound as per the usual rules, the usage here is
// a special exception with the following notes in place. When dealing with a potential
// race from a hardware or code outside kernel (e.g. user-space program), we need that
// write on a valid memory is not UB. Currently write_volatile() is used for this, and the
// rationale behind is that it should generate the same code as WRITE_ONCE() which the
// kernel already relies on to avoid UB on data races. Note that the usage of
// write_volatile() is limited to this particular case, it cannot be used to prevent
// the UB caused by racing between two kernel functions nor do they provide atomicity.
unsafe { field.write_volatile(val) }
}
}
/// Note that the device configured to do DMA must be halted before this object is dropped.
impl<T: AsBytes + FromBytes> Drop for CoherentAllocation<T> {
fn drop(&mut self) {
let size = self.count * core::mem::size_of::<T>();
// SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`.
// The cpu address, and the dma handle are valid due to the type invariants on
// `CoherentAllocation`.
unsafe {
bindings::dma_free_attrs(
self.dev.as_raw(),
size,
self.cpu_addr as _,
self.dma_handle,
self.dma_attrs.as_raw(),
)
}
}
}
// SAFETY: It is safe to send a `CoherentAllocation` to another thread if `T`
// can be sent to another thread.
unsafe impl<T: AsBytes + FromBytes + Send> Send for CoherentAllocation<T> {}
/// Reads a field of an item from an allocated region of structs.
///
/// # Examples
///
/// ```
/// use kernel::device::Device;
/// use kernel::dma::{attrs::*, CoherentAllocation};
///
/// struct MyStruct { field: u32, }
///
/// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
/// unsafe impl kernel::transmute::FromBytes for MyStruct{};
/// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
///
/// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
/// let whole = kernel::dma_read!(alloc[2]);
/// let field = kernel::dma_read!(alloc[1].field);
/// # Ok::<(), Error>(()) }
/// ```
#[macro_export]
macro_rules! dma_read {
($dma:expr, $idx: expr, $($field:tt)*) => {{
let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?;
// SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
// dereferenced. The compiler also further validates the expression on whether `field`
// is a member of `item` when expanded by the macro.
unsafe {
let ptr_field = ::core::ptr::addr_of!((*item) $($field)*);
$crate::dma::CoherentAllocation::field_read(&$dma, ptr_field)
}
}};
($dma:ident [ $idx:expr ] $($field:tt)* ) => {
$crate::dma_read!($dma, $idx, $($field)*);
};
($($dma:ident).* [ $idx:expr ] $($field:tt)* ) => {
$crate::dma_read!($($dma).*, $idx, $($field)*);
};
}
/// Writes to a field of an item from an allocated region of structs.
///
/// # Examples
///
/// ```
/// use kernel::device::Device;
/// use kernel::dma::{attrs::*, CoherentAllocation};
///
/// struct MyStruct { member: u32, }
///
/// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
/// unsafe impl kernel::transmute::FromBytes for MyStruct{};
/// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
///
/// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
/// kernel::dma_write!(alloc[2].member = 0xf);
/// kernel::dma_write!(alloc[1] = MyStruct { member: 0xf });
/// # Ok::<(), Error>(()) }
/// ```
#[macro_export]
macro_rules! dma_write {
($dma:ident [ $idx:expr ] $($field:tt)*) => {{
$crate::dma_write!($dma, $idx, $($field)*);
}};
($($dma:ident).* [ $idx:expr ] $($field:tt)* ) => {{
$crate::dma_write!($($dma).*, $idx, $($field)*);
}};
($dma:expr, $idx: expr, = $val:expr) => {
let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?;
// SAFETY: `item_from_index` ensures that `item` is always a valid item.
unsafe { $crate::dma::CoherentAllocation::field_write(&$dma, item, $val) }
};
($dma:expr, $idx: expr, $(.$field:ident)* = $val:expr) => {
let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?;
// SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
// dereferenced. The compiler also further validates the expression on whether `field`
// is a member of `item` when expanded by the macro.
unsafe {
let ptr_field = ::core::ptr::addr_of_mut!((*item) $(.$field)*);
$crate::dma::CoherentAllocation::field_write(&$dma, ptr_field, $val)
}
};
}

View File

@@ -6,9 +6,9 @@
//! register using the [`Registration`] class.
use crate::error::{Error, Result};
use crate::{device, init::PinInit, of, str::CStr, try_pin_init, types::Opaque, ThisModule};
use crate::{device, of, str::CStr, try_pin_init, types::Opaque, ThisModule};
use core::pin::Pin;
use macros::{pin_data, pinned_drop};
use pin_init::{pin_data, pinned_drop, PinInit};
/// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform,
/// Amba, etc.) to provide the corresponding subsystem specific implementation to register /
@@ -114,7 +114,7 @@ macro_rules! module_driver {
impl $crate::InPlaceModule for DriverModule {
fn init(
module: &'static $crate::ThisModule
) -> impl $crate::init::PinInit<Self, $crate::error::Error> {
) -> impl ::pin_init::PinInit<Self, $crate::error::Error> {
$crate::try_pin_init!(Self {
_driver <- $crate::driver::Registration::new(
<Self as $crate::ModuleMetadata>::NAME,

Some files were not shown because too many files have changed in this diff Show More