From 73243a8a27a6726dba6c5c2c08774122bfa66da5 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 5 Jun 2021 17:40:42 +0100 Subject: [PATCH 1/3] rust: generate bindings for helpers Automatically generate rust bindings for helper functions via bindgen. The corresponding Rust bindings will have their `rust_helper_` prefix removed, so Rust code can call `bindings::foo` regardless whether `foo` is directly exposed or exposed via a helper. When both a directly exposed symbol and a helper exists, the directly exposed symbol will take precedence. Signed-off-by: Gary Guo --- Makefile | 1 + rust/.gitignore | 1 + rust/Makefile | 31 +++++++++++++++++++++++-------- rust/kernel/bindings.rs | 24 +++++++++++++++++++++--- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index b49f78b027afe4..b56269fa95eb2a 100644 --- a/Makefile +++ b/Makefile @@ -1834,6 +1834,7 @@ rustfmt: -o -path $(abs_objtree)/rust/test -prune \ | grep -Fv $(abs_srctree)/rust/alloc \ | grep -Fv $(abs_objtree)/rust/test \ + | grep -Fv generated \ | xargs $(RUSTFMT) $(rustfmt_flags) rustfmtcheck: rustfmt_flags = --check diff --git a/rust/.gitignore b/rust/.gitignore index c6186b71e1c3fb..168cb26a31b999 100644 --- a/rust/.gitignore +++ b/rust/.gitignore @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 bindings_generated.rs +bindings_helpers_generated.rs exports_*_generated.h doc/ test/ diff --git a/rust/Makefile b/rust/Makefile index 44736e683cf87d..7c18b06d47e332 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -5,7 +5,7 @@ extra-$(CONFIG_RUST) += exports_core_generated.h extra-$(CONFIG_RUST) += libmacros.so -extra-$(CONFIG_RUST) += bindings_generated.rs +extra-$(CONFIG_RUST) += bindings_generated.rs bindings_helpers_generated.rs obj-$(CONFIG_RUST) += alloc.o kernel.o extra-$(CONFIG_RUST) += exports_alloc_generated.h exports_kernel_generated.h @@ -30,7 +30,7 @@ endif quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $< cmd_rustdoc = \ - RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \ + OBJTREE=$(abspath $(objtree)) \ $(RUSTDOC) $(if $(rustdoc_host),,$(rust_cross_flags)) \ $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rust_flags))) \ $(rustc_target_flags) -L $(objtree)/rust \ @@ -73,12 +73,13 @@ rustdoc-kernel: private rustc_target_flags = --extern alloc \ --extern macros=$(objtree)/rust/libmacros.so rustdoc-kernel: $(srctree)/rust/kernel/lib.rs rustdoc-core \ rustdoc-macros rustdoc-compiler_builtins rustdoc-alloc \ - $(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs FORCE + $(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs \ + $(objtree)/rust/bindings_helpers_generated.rs FORCE $(call if_changed,rustdoc) quiet_cmd_rustc_test_library = RUSTC TL $< cmd_rustc_test_library = \ - RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \ + OBJTREE=$(abspath $(objtree)) \ $(RUSTC) $(filter-out --sysroot=%, $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rust_flags)))) \ $(rustc_target_flags) --crate-type $(if $(rustc_test_library_proc),proc-macro,rlib) \ --out-dir $(objtree)/rust/test/ --cfg testlib \ @@ -95,7 +96,7 @@ rusttestlib-macros: $(srctree)/rust/macros/lib.rs rusttest-prepare FORCE quiet_cmd_rustdoc_test = RUSTDOC T $< cmd_rustdoc_test = \ - RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \ + OBJTREE=$(abspath $(objtree)) \ $(RUSTDOC) --test $(filter-out --sysroot=%, $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rust_flags)))) \ $(rustc_target_flags) $(rustdoc_test_target_flags) \ --sysroot $(objtree)/rust/test/sysroot $(rustdoc_test_quiet) \ @@ -107,7 +108,7 @@ quiet_cmd_rustdoc_test = RUSTDOC T $< # so for the moment we skip `-Cpanic=abort`. quiet_cmd_rustc_test = RUSTC T $< cmd_rustc_test = \ - RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \ + OBJTREE=$(abspath $(objtree)) \ $(RUSTC) --test $(filter-out --sysroot=%, $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rust_flags)))) \ $(rustc_target_flags) --out-dir $(objtree)/rust/test \ --sysroot $(objtree)/rust/test/sysroot \ @@ -230,6 +231,19 @@ $(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h $(srctree)/rust/bindgen_parameters FORCE $(call if_changed_dep,bindgen) +quiet_cmd_bindgen_helper = BINDGEN $@ + cmd_bindgen_helper = \ + $(BINDGEN) $< --blacklist-type '.*' --whitelist-var '' \ + --whitelist-function 'rust_helper_.*' \ + --use-core --with-derive-default --ctypes-prefix c_types \ + --no-debug '.*' \ + --size_t-is-usize -o $@ -- $(bindgen_c_flags_final) \ + -I$(objtree)/rust/ -DMODULE; \ + sed -Ei 's/pub fn rust_helper_([a-zA-Z0-9_]*)/\#[link_name="rust_helper_\1"]\n pub fn \1/g' $@ + +$(objtree)/rust/bindings_helpers_generated.rs: $(srctree)/rust/helpers.c FORCE + $(call if_changed_dep,bindgen_helper) + quiet_cmd_exports = EXPORTS $@ cmd_exports = \ $(NM) -p --defined-only $< \ @@ -267,7 +281,7 @@ $(objtree)/rust/libmacros.so: $(srctree)/rust/macros/lib.rs \ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L $@ cmd_rustc_library = \ - RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \ + OBJTREE=$(abspath $(objtree)) \ $(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \ $(rust_flags) $(rust_cross_flags) $(rustc_target_flags) \ --crate-type rlib --out-dir $(objtree)/rust/ -L $(objtree)/rust/ \ @@ -305,7 +319,8 @@ $(objtree)/rust/kernel.o: private rustc_target_flags = --extern alloc \ --extern macros=$(objtree)/rust/libmacros.so $(objtree)/rust/kernel.o: $(srctree)/rust/kernel/lib.rs $(objtree)/rust/alloc.o \ $(objtree)/rust/build_error.o \ - $(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs FORCE + $(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs \ + $(objtree)/rust/bindings_helpers_generated.rs FORCE $(call if_changed_dep,rustc_library) # Targets that need to expand twice diff --git a/rust/kernel/bindings.rs b/rust/kernel/bindings.rs index 93290926ceca14..08182f94765474 100644 --- a/rust/kernel/bindings.rs +++ b/rust/kernel/bindings.rs @@ -8,8 +8,7 @@ #![cfg_attr(test, allow(deref_nullptr))] #![cfg_attr(test, allow(unaligned_references))] #![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))] - -#[allow( +#![allow( clippy::all, non_camel_case_types, non_upper_case_globals, @@ -17,10 +16,29 @@ improper_ctypes, unsafe_op_in_unsafe_fn )] + mod bindings_raw { + // Use glob import here to expose all helpers. + // Symbols defined within the module will take precedence to the glob import. + pub use super::bindings_helper::*; + use crate::c_types; + include!(concat!(env!("OBJTREE"), "/rust/bindings_generated.rs")); +} + +// When both a directly exposed symbol and a helper exists for the same function, +// the directly exposed symbol is preferred and the helper becomes dead code, so +// ignore the warning here. +#[allow(dead_code)] +mod bindings_helper { + // Import the generated bindings for types. + use super::bindings_raw::*; use crate::c_types; - include!(env!("RUST_BINDINGS_FILE")); + include!(concat!( + env!("OBJTREE"), + "/rust/bindings_helpers_generated.rs" + )); } + pub use bindings_raw::*; pub const GFP_KERNEL: gfp_t = BINDINGS_GFP_KERNEL; From 5444b8b2ad903d4d85bc01519b16fea3555b1cb7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 29 Jul 2021 19:23:43 +0100 Subject: [PATCH 2/3] rust: use the generated helper bindings Signed-off-by: Gary Guo --- rust/helpers.c | 23 ++++++++++++----------- rust/kernel/error.rs | 25 +++++++------------------ rust/kernel/io_mem.rs | 31 ++++++------------------------- rust/kernel/iov_iter.rs | 20 +++----------------- rust/kernel/lib.rs | 9 +++++---- rust/kernel/pages.rs | 20 +++----------------- rust/kernel/platdev.rs | 17 ++--------------- rust/kernel/power.rs | 7 +------ rust/kernel/rbtree.rs | 10 +--------- rust/kernel/security.rs | 33 +++++---------------------------- rust/kernel/sync/arc.rs | 12 +++--------- rust/kernel/sync/condvar.rs | 6 +----- rust/kernel/sync/mod.rs | 8 ++------ rust/kernel/sync/mutex.rs | 8 +++----- rust/kernel/sync/spinlock.rs | 19 ++++--------------- rust/kernel/task.rs | 21 +++++---------------- rust/kernel/user_ptr.rs | 24 ++++-------------------- 17 files changed, 67 insertions(+), 226 deletions(-) diff --git a/rust/helpers.c b/rust/helpers.c index 5fa1267dc6466f..36060f1f953d2d 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -13,7 +13,7 @@ #include #include -void rust_helper_BUG(void) +__noreturn void rust_helper_BUG(void) { BUG(); } @@ -91,8 +91,8 @@ void rust_helper_writeq(u64 value, volatile void __iomem *addr) EXPORT_SYMBOL_GPL(rust_helper_writeq); #endif -void rust_helper_spin_lock_init(spinlock_t *lock, const char *name, - struct lock_class_key *key) +void rust_helper___spin_lock_init(spinlock_t *lock, const char *name, + struct lock_class_key *key) { #ifdef CONFIG_DEBUG_SPINLOCK __spin_lock_init(lock, name, key); @@ -100,7 +100,7 @@ void rust_helper_spin_lock_init(spinlock_t *lock, const char *name, spin_lock_init(lock); #endif } -EXPORT_SYMBOL_GPL(rust_helper_spin_lock_init); +EXPORT_SYMBOL_GPL(rust_helper___spin_lock_init); void rust_helper_spin_lock(spinlock_t *lock) { @@ -162,22 +162,23 @@ size_t rust_helper_copy_to_iter(const void *addr, size_t bytes, struct iov_iter } EXPORT_SYMBOL_GPL(rust_helper_copy_to_iter); -bool rust_helper_is_err(__force const void *ptr) +bool rust_helper_IS_ERR(__force const void *ptr) { return IS_ERR(ptr); } -EXPORT_SYMBOL_GPL(rust_helper_is_err); +EXPORT_SYMBOL_GPL(rust_helper_IS_ERR); -long rust_helper_ptr_err(__force const void *ptr) +long rust_helper_PTR_ERR(__force const void *ptr) { return PTR_ERR(ptr); } -EXPORT_SYMBOL_GPL(rust_helper_ptr_err); +EXPORT_SYMBOL_GPL(rust_helper_PTR_ERR); const char *rust_helper_errname(int err) { return errname(err); } +EXPORT_SYMBOL_GPL(rust_helper_errname); void rust_helper_mutex_lock(struct mutex *lock) { @@ -200,11 +201,11 @@ rust_helper_platform_set_drvdata(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(rust_helper_platform_set_drvdata); -refcount_t rust_helper_refcount_new(void) +refcount_t rust_helper_REFCOUNT_INIT(int n) { - return (refcount_t)REFCOUNT_INIT(1); + return (refcount_t)REFCOUNT_INIT(n); } -EXPORT_SYMBOL_GPL(rust_helper_refcount_new); +EXPORT_SYMBOL_GPL(rust_helper_REFCOUNT_INIT); void rust_helper_refcount_inc(refcount_t *r) { diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index b9ca1e87980c36..ec370efb9cb7da 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -351,11 +351,8 @@ impl Error { impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - extern "C" { - fn rust_helper_errname(err: c_types::c_int) -> *const c_types::c_char; - } // SAFETY: FFI call. - let name = unsafe { rust_helper_errname(-self.0) }; + let name = unsafe { bindings::errname(-self.0) }; if name.is_null() { // Print out number if no name can be found. @@ -452,7 +449,7 @@ where /// ) -> c_types::c_int { /// from_kernel_result! { /// let ptr = devm_alloc(pdev)?; -/// rust_helper_platform_set_drvdata(pdev, ptr); +/// bindings::platform_set_drvdata(pdev, ptr); /// Ok(0) /// } /// } @@ -496,28 +493,20 @@ macro_rules! from_kernel_result { // TODO: remove `dead_code` marker once an in-kernel client is available. #[allow(dead_code)] pub(crate) fn from_kernel_err_ptr(ptr: *mut T) -> Result<*mut T> { - extern "C" { - #[allow(improper_ctypes)] - fn rust_helper_is_err(ptr: *const c_types::c_void) -> bool; - - #[allow(improper_ctypes)] - fn rust_helper_ptr_err(ptr: *const c_types::c_void) -> c_types::c_long; - } - // CAST: casting a pointer to `*const c_types::c_void` is always valid. let const_ptr: *const c_types::c_void = ptr.cast(); // SAFETY: the FFI function does not deref the pointer. - if unsafe { rust_helper_is_err(const_ptr) } { + if unsafe { bindings::IS_ERR(const_ptr) } { // SAFETY: the FFI function does not deref the pointer. - let err = unsafe { rust_helper_ptr_err(const_ptr) }; - // CAST: if `rust_helper_is_err()` returns `true`, - // then `rust_helper_ptr_err()` is guaranteed to return a + let err = unsafe { bindings::PTR_ERR(const_ptr) }; + // CAST: if `IS_ERR()` returns `true`, + // then `PTR_ERR()` is guaranteed to return a // negative value greater-or-equal to `-bindings::MAX_ERRNO`, // which always fits in an `i16`, as per the invariant above. // And an `i16` always fits in an `i32`. So casting `err` to // an `i32` can never overflow, and is always valid. // - // SAFETY: `rust_helper_is_err()` ensures `err` is a + // SAFETY: `IS_ERR()` ensures `err` is a // negative value greater-or-equal to `-bindings::MAX_ERRNO` return Err(unsafe { Error::from_kernel_errno_unchecked(err as i32) }); } diff --git a/rust/kernel/io_mem.rs b/rust/kernel/io_mem.rs index 23c5636e841d09..c8277004dc0ba0 100644 --- a/rust/kernel/io_mem.rs +++ b/rust/kernel/io_mem.rs @@ -4,26 +4,9 @@ //! //! C header: [`include/asm-generic/io.h`](../../../../include/asm-generic/io.h) -use crate::{bindings, c_types, Error, Result}; +use crate::{bindings, Error, Result}; use core::convert::TryInto; -extern "C" { - fn rust_helper_ioremap( - offset: bindings::resource_size_t, - size: c_types::c_ulong, - ) -> *mut c_types::c_void; - - fn rust_helper_readb(addr: *const c_types::c_void) -> u8; - fn rust_helper_readw(addr: *const c_types::c_void) -> u16; - fn rust_helper_readl(addr: *const c_types::c_void) -> u32; - fn rust_helper_readq(addr: *const c_types::c_void) -> u64; - - fn rust_helper_writeb(value: u8, addr: *mut c_types::c_void); - fn rust_helper_writew(value: u16, addr: *mut c_types::c_void); - fn rust_helper_writel(value: u32, addr: *mut c_types::c_void); - fn rust_helper_writeq(value: u64, addr: *mut c_types::c_void); -} - /// Represents a memory resource. pub struct Resource { offset: bindings::resource_size_t, @@ -88,7 +71,7 @@ macro_rules! define_read { // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above // guarantees that the code won't build if `offset` makes the read go out of bounds // (including the type size). - unsafe { concat_idents!(rust_helper_, $name)(ptr as _) } + unsafe { bindings::$name(ptr as _) } } /// Reads IO data from the given offset. @@ -102,7 +85,7 @@ macro_rules! define_read { // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above // returns an error if `offset` would make the read go out of bounds (including the // type size). - Ok(unsafe { concat_idents!(rust_helper_, $name)(ptr as _) }) + Ok(unsafe { bindings::$name(ptr as _) }) } }; } @@ -118,7 +101,7 @@ macro_rules! define_write { // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above // guarantees that the code won't link if `offset` makes the write go out of bounds // (including the type size). - unsafe { concat_idents!(rust_helper_, $name)(value, ptr as _) } + unsafe { bindings::$name(value, ptr as _) } } /// Writes IO data to the given offset. @@ -132,7 +115,7 @@ macro_rules! define_write { // SAFETY: The type invariants guarantee that `ptr` is a valid pointer. The check above // returns an error if `offset` would make the write go out of bounds (including the // type size). - unsafe { concat_idents!(rust_helper_, $name)(value, ptr as _) }; + unsafe { bindings::$name(value, ptr as _) }; Ok(()) } }; @@ -165,9 +148,7 @@ impl IoMem { // Try to map the resource. // SAFETY: Just mapping the memory range. - // TODO: Remove `into` call below (and disabling of clippy warning) once #465 is fixed. - #[allow(clippy::complexity)] - let addr = unsafe { rust_helper_ioremap(res.offset, res.size.into()) }; + let addr = unsafe { bindings::ioremap(res.offset, res.size as _) }; if addr.is_null() { Err(Error::ENOMEM) } else { diff --git a/rust/kernel/iov_iter.rs b/rust/kernel/iov_iter.rs index d778e1ac976075..fe738c529b8485 100644 --- a/rust/kernel/iov_iter.rs +++ b/rust/kernel/iov_iter.rs @@ -5,26 +5,12 @@ //! C header: [`include/linux/uio.h`](../../../../include/linux/uio.h) use crate::{ - bindings, c_types, + bindings, error::Error, io_buffer::{IoBufferReader, IoBufferWriter}, Result, }; -extern "C" { - fn rust_helper_copy_to_iter( - addr: *const c_types::c_void, - bytes: usize, - i: *mut bindings::iov_iter, - ) -> usize; - - fn rust_helper_copy_from_iter( - addr: *mut c_types::c_void, - bytes: usize, - i: *mut bindings::iov_iter, - ) -> usize; -} - /// Wraps the kernel's `struct iov_iter`. /// /// # Invariants @@ -70,7 +56,7 @@ impl IoBufferWriter for IovIter { } unsafe fn write_raw(&mut self, data: *const u8, len: usize) -> Result { - let res = unsafe { rust_helper_copy_to_iter(data as _, len, self.ptr) }; + let res = unsafe { bindings::copy_to_iter(data as _, len, self.ptr) }; if res != len { Err(Error::EFAULT) } else { @@ -85,7 +71,7 @@ impl IoBufferReader for IovIter { } unsafe fn read_raw(&mut self, out: *mut u8, len: usize) -> Result { - let res = unsafe { rust_helper_copy_from_iter(out as _, len, self.ptr) }; + let res = unsafe { bindings::copy_from_iter(out as _, len, self.ptr) }; if res != len { Err(Error::EFAULT) } else { diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index c6bf9043afb693..cda5f0e331c4ff 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -232,10 +232,11 @@ macro_rules! container_of { #[cfg(not(any(testlib, test)))] #[panic_handler] fn panic(info: &core::panic::PanicInfo<'_>) -> ! { - extern "C" { - fn rust_helper_BUG() -> !; - } pr_emerg!("{}\n", info); // SAFETY: FFI call. - unsafe { rust_helper_BUG() }; + unsafe { bindings::BUG() }; + // Bindgen currently does not recognize `__noreturn` so `BUG` returns `()` + // instead of `!`. + // https://github.com/rust-lang/rust-bindgen/issues/2094 + loop {} } diff --git a/rust/kernel/pages.rs b/rust/kernel/pages.rs index 4f45bef09bca4e..de8358629fdd95 100644 --- a/rust/kernel/pages.rs +++ b/rust/kernel/pages.rs @@ -10,20 +10,6 @@ use crate::{ }; use core::{marker::PhantomData, ptr}; -extern "C" { - #[allow(improper_ctypes)] - fn rust_helper_alloc_pages( - gfp_mask: bindings::gfp_t, - order: c_types::c_uint, - ) -> *mut bindings::page; - - #[allow(improper_ctypes)] - fn rust_helper_kmap(page: *mut bindings::page) -> *mut c_types::c_void; - - #[allow(improper_ctypes)] - fn rust_helper_kunmap(page: *mut bindings::page); -} - /// A set of physical pages. /// /// `Pages` holds a reference to a set of pages of order `ORDER`. Having the order as a generic @@ -42,7 +28,7 @@ impl Pages { // TODO: Consider whether we want to allow callers to specify flags. // SAFETY: This only allocates pages. We check that it succeeds in the next statement. let pages = unsafe { - rust_helper_alloc_pages( + bindings::alloc_pages( bindings::GFP_KERNEL | bindings::__GFP_ZERO | bindings::__GFP_HIGHMEM, ORDER, ) @@ -141,7 +127,7 @@ impl Pages { let page = unsafe { self.pages.add(index) }; // SAFETY: `page` is valid based on the checks above. - let ptr = unsafe { rust_helper_kmap(page) }; + let ptr = unsafe { bindings::kmap(page) }; if ptr.is_null() { return None; } @@ -171,6 +157,6 @@ impl Drop for PageMapping<'_> { fn drop(&mut self) { // SAFETY: An instance of `PageMapping` is created only when `kmap` succeeded for the given // page, so it is safe to unmap it here. - unsafe { rust_helper_kunmap(self.page) }; + unsafe { bindings::kunmap(self.page) }; } } diff --git a/rust/kernel/platdev.rs b/rust/kernel/platdev.rs index 5f306b61321e36..d55adb01059af7 100644 --- a/rust/kernel/platdev.rs +++ b/rust/kernel/platdev.rs @@ -29,19 +29,6 @@ pub struct Registration { // (it is fine for multiple threads to have a shared reference to it). unsafe impl Sync for Registration {} -extern "C" { - #[allow(improper_ctypes)] - fn rust_helper_platform_get_drvdata( - pdev: *const bindings::platform_device, - ) -> *mut c_types::c_void; - - #[allow(improper_ctypes)] - fn rust_helper_platform_set_drvdata( - pdev: *mut bindings::platform_device, - data: *mut c_types::c_void, - ); -} - extern "C" fn probe_callback( pdev: *mut bindings::platform_device, ) -> c_types::c_int { @@ -52,7 +39,7 @@ extern "C" fn probe_callback( let drv_data = drv_data.into_pointer() as *mut c_types::c_void; // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer. unsafe { - rust_helper_platform_set_drvdata(pdev, drv_data); + bindings::platform_set_drvdata(pdev, drv_data); } Ok(0) } @@ -65,7 +52,7 @@ extern "C" fn remove_callback( // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer. let device_id = unsafe { (*pdev).id }; // SAFETY: `pdev` is guaranteed to be a valid, non-null pointer. - let ptr = unsafe { rust_helper_platform_get_drvdata(pdev) }; + let ptr = unsafe { bindings::platform_get_drvdata(pdev) }; // SAFETY: // - we allocated this pointer using `P::DrvData::into_pointer`, // so it is safe to turn back into a `P::DrvData`. diff --git a/rust/kernel/power.rs b/rust/kernel/power.rs index d364f16a2589a6..f145c41aeaea0b 100644 --- a/rust/kernel/power.rs +++ b/rust/kernel/power.rs @@ -7,11 +7,6 @@ use crate::{bindings, c_types, from_kernel_result, sync::Ref, types::PointerWrapper, Result}; use core::{marker::PhantomData, ops::Deref}; -extern "C" { - #[allow(improper_ctypes)] - fn rust_helper_dev_get_drvdata(dev: *mut bindings::device) -> *mut c_types::c_void; -} - /// Corresponds to the kernel's `struct dev_pm_ops`. /// /// It is meant to be implemented by drivers that support power-management operations. @@ -47,7 +42,7 @@ macro_rules! pm_callback { ) -> c_types::c_int { from_kernel_result! { // SAFETY: `dev` is valid as it was passed in by the C portion. - let ptr = unsafe { rust_helper_dev_get_drvdata(dev) }; + let ptr = unsafe { bindings::dev_get_drvdata(dev) }; // SAFETY: By the safety requirements of `OpsTable::build`, we know that `ptr` came // from a previous call to `T::Data::into_pointer`. let data = unsafe { T::Data::borrow(ptr) }; diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs index 630865369508c4..880252e9cde71a 100644 --- a/rust/kernel/rbtree.rs +++ b/rust/kernel/rbtree.rs @@ -16,14 +16,6 @@ use core::{ ptr::{addr_of_mut, NonNull}, }; -extern "C" { - fn rust_helper_rb_link_node( - node: *mut bindings::rb_node, - parent: *const bindings::rb_node, - rb_link: *mut *mut bindings::rb_node, - ); -} - struct Node { links: bindings::rb_node, key: K, @@ -289,7 +281,7 @@ impl RBTree { // "forgot" it with `Box::into_raw`. // SAFETY: All pointers are non-null and valid (`*new_link` is null, but `new_link` is a // mutable reference). - unsafe { rust_helper_rb_link_node(node_links, parent, new_link) }; + unsafe { bindings::rb_link_node(node_links, parent, new_link) }; // SAFETY: All pointers are valid. `node` has just been inserted into the tree. unsafe { bindings::rb_insert_color(node_links, &mut self.root) }; diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs index c38b0dceb345aa..7161ec072cbaa7 100644 --- a/rust/kernel/security.rs +++ b/rust/kernel/security.rs @@ -4,36 +4,13 @@ //! //! C header: [`include/linux/security.h`](../../../../include/linux/security.h). -use crate::{bindings, c_types, error::Error, file::File, task::Task, Result}; - -extern "C" { - #[allow(improper_ctypes)] - fn rust_helper_security_binder_set_context_mgr( - mgr: *mut bindings::task_struct, - ) -> c_types::c_int; - #[allow(improper_ctypes)] - fn rust_helper_security_binder_transaction( - from: *mut bindings::task_struct, - to: *mut bindings::task_struct, - ) -> c_types::c_int; - #[allow(improper_ctypes)] - fn rust_helper_security_binder_transfer_binder( - from: *mut bindings::task_struct, - to: *mut bindings::task_struct, - ) -> c_types::c_int; - #[allow(improper_ctypes)] - fn rust_helper_security_binder_transfer_file( - from: *mut bindings::task_struct, - to: *mut bindings::task_struct, - file: *mut bindings::file, - ) -> c_types::c_int; -} +use crate::{bindings, error::Error, file::File, task::Task, Result}; /// Calls the security modules to determine if the given task can become the manager of a binder /// context. pub fn binder_set_context_mgr(mgr: &Task) -> Result { // SAFETY: By the `Task` invariants, `mgr.ptr` is valid. - let ret = unsafe { rust_helper_security_binder_set_context_mgr(mgr.ptr) }; + let ret = unsafe { bindings::security_binder_set_context_mgr(mgr.ptr) }; if ret != 0 { Err(Error::from_kernel_errno(ret)) } else { @@ -45,7 +22,7 @@ pub fn binder_set_context_mgr(mgr: &Task) -> Result { /// task `to`. pub fn binder_transaction(from: &Task, to: &Task) -> Result { // SAFETY: By the `Task` invariants, `from.ptr` and `to.ptr` are valid. - let ret = unsafe { rust_helper_security_binder_transaction(from.ptr, to.ptr) }; + let ret = unsafe { bindings::security_binder_transaction(from.ptr, to.ptr) }; if ret != 0 { Err(Error::from_kernel_errno(ret)) } else { @@ -57,7 +34,7 @@ pub fn binder_transaction(from: &Task, to: &Task) -> Result { /// (owned by itself or other processes) to task `to` through a binder transaction. pub fn binder_transfer_binder(from: &Task, to: &Task) -> Result { // SAFETY: By the `Task` invariants, `from.ptr` and `to.ptr` are valid. - let ret = unsafe { rust_helper_security_binder_transfer_binder(from.ptr, to.ptr) }; + let ret = unsafe { bindings::security_binder_transfer_binder(from.ptr, to.ptr) }; if ret != 0 { Err(Error::from_kernel_errno(ret)) } else { @@ -70,7 +47,7 @@ pub fn binder_transfer_binder(from: &Task, to: &Task) -> Result { pub fn binder_transfer_file(from: &Task, to: &Task, file: &File) -> Result { // SAFETY: By the `Task` invariants, `from.ptr` and `to.ptr` are valid. Similarly, by the // `File` invariants, `file.ptr` is also valid. - let ret = unsafe { rust_helper_security_binder_transfer_file(from.ptr, to.ptr, file.ptr) }; + let ret = unsafe { bindings::security_binder_transfer_file(from.ptr, to.ptr, file.ptr) }; if ret != 0 { Err(Error::from_kernel_errno(ret)) } else { diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 14e99ff172592a..1e0650165d987d 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -28,12 +28,6 @@ use core::{ ptr::{self, NonNull}, }; -extern "C" { - fn rust_helper_refcount_new() -> bindings::refcount_t; - fn rust_helper_refcount_inc(r: *mut bindings::refcount_t); - fn rust_helper_refcount_dec_and_test(r: *mut bindings::refcount_t) -> bool; -} - /// A reference-counted pointer to an instance of `T`. /// /// The reference count is incremented when new instances of [`Ref`] are created, and decremented @@ -88,7 +82,7 @@ impl Ref { // INVARIANT: The refcount is initialised to a non-zero value. let mut inner = Box::try_new(RefInner { // SAFETY: Just an FFI call that returns a `refcount_t` initialised to 1. - refcount: UnsafeCell::new(unsafe { rust_helper_refcount_new() }), + refcount: UnsafeCell::new(unsafe { bindings::REFCOUNT_INIT(1) }), data: contents, })?; @@ -219,7 +213,7 @@ impl Clone for Ref { // INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero. // SAFETY: By the type invariant, there is necessarily a reference to the object, so it is // safe to increment the refcount. - unsafe { rust_helper_refcount_inc(self.ptr.as_ref().refcount.get()) }; + unsafe { bindings::refcount_inc(self.ptr.as_ref().refcount.get()) }; Self { ptr: self.ptr, _p: PhantomData, @@ -246,7 +240,7 @@ impl Drop for Ref { // INVARIANT: If the refcount reaches zero, there are no other instances of `Ref`, and // this instance is being dropped, so the broken invariant is not observable. // SAFETY: Also by the type invariant, we are allowed to decrement the refcount. - let is_zero = unsafe { rust_helper_refcount_dec_and_test(refcount) }; + let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) }; if is_zero { // The count reached zero, we must free the memory. // diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index ba23a944be9ea7..8add1b5be39ce9 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -9,10 +9,6 @@ use super::{Guard, Lock, NeedsLockClass}; use crate::{bindings, str::CStr, task::Task}; use core::{cell::UnsafeCell, marker::PhantomPinned, mem::MaybeUninit, pin::Pin}; -extern "C" { - fn rust_helper_init_wait(wq: *mut bindings::wait_queue_entry); -} - /// Safely initialises a [`CondVar`] with the given name, generating a new lock class. #[macro_export] macro_rules! condvar_init { @@ -69,7 +65,7 @@ impl CondVar { let mut wait = MaybeUninit::::uninit(); // SAFETY: `wait` points to valid memory. - unsafe { rust_helper_init_wait(wait.as_mut_ptr()) }; + unsafe { bindings::init_wait(wait.as_mut_ptr()) }; // SAFETY: Both `wait` and `wait_list` point to valid memory. unsafe { diff --git a/rust/kernel/sync/mod.rs b/rust/kernel/sync/mod.rs index ce863109c06eb8..56eed3d96e69c3 100644 --- a/rust/kernel/sync/mod.rs +++ b/rust/kernel/sync/mod.rs @@ -20,8 +20,8 @@ //! pr_info!("{}\n", *data.lock()); //! ``` +use crate::bindings; use crate::str::CStr; -use crate::{bindings, c_types}; use core::pin::Pin; mod arc; @@ -38,10 +38,6 @@ pub use locked_by::LockedBy; pub use mutex::Mutex; pub use spinlock::SpinLock; -extern "C" { - fn rust_helper_cond_resched() -> c_types::c_int; -} - /// Safely initialises an object that has an `init` function that takes a name and a lock class as /// arguments, examples of these are [`Mutex`] and [`SpinLock`]. Each of them also provides a more /// specialised name that uses this macro. @@ -80,5 +76,5 @@ pub trait NeedsLockClass { /// Reschedules the caller's task if needed. pub fn cond_resched() -> bool { // SAFETY: No arguments, reschedules `current` if needed. - unsafe { rust_helper_cond_resched() != 0 } + unsafe { bindings::cond_resched() != 0 } } diff --git a/rust/kernel/sync/mutex.rs b/rust/kernel/sync/mutex.rs index fa886090fe1926..4ceca07b201e89 100644 --- a/rust/kernel/sync/mutex.rs +++ b/rust/kernel/sync/mutex.rs @@ -77,17 +77,15 @@ impl NeedsLockClass for Mutex { } } -extern "C" { - fn rust_helper_mutex_lock(mutex: *mut bindings::mutex); -} - impl Lock for Mutex { type Inner = T; type GuardContext = (); fn lock_noguard(&self) { // SAFETY: `mutex` points to valid memory. - unsafe { rust_helper_mutex_lock(self.mutex.get()) }; + unsafe { + bindings::mutex_lock(self.mutex.get()); + } } unsafe fn unlock(&self, _: &mut ()) { diff --git a/rust/kernel/sync/spinlock.rs b/rust/kernel/sync/spinlock.rs index 4866abb75074dd..11b918dab3a04c 100644 --- a/rust/kernel/sync/spinlock.rs +++ b/rust/kernel/sync/spinlock.rs @@ -7,21 +7,10 @@ //! See . use super::{Guard, Lock, NeedsLockClass}; +use crate::bindings; use crate::str::CStr; -use crate::{bindings, c_types}; use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin}; -extern "C" { - #[allow(improper_ctypes)] - fn rust_helper_spin_lock_init( - lock: *mut bindings::spinlock_t, - name: *const c_types::c_char, - key: *mut bindings::lock_class_key, - ); - fn rust_helper_spin_lock(lock: *mut bindings::spinlock); - fn rust_helper_spin_unlock(lock: *mut bindings::spinlock); -} - /// Safely initialises a [`SpinLock`] with the given name, generating a new lock class. #[macro_export] macro_rules! spinlock_init { @@ -87,7 +76,7 @@ impl SpinLock { impl NeedsLockClass for SpinLock { unsafe fn init(self: Pin<&mut Self>, name: &'static CStr, key: *mut bindings::lock_class_key) { - unsafe { rust_helper_spin_lock_init(self.spin_lock.get(), name.as_char_ptr(), key) }; + unsafe { bindings::__spin_lock_init(self.spin_lock.get(), name.as_char_ptr(), key) }; } } @@ -97,13 +86,13 @@ impl Lock for SpinLock { fn lock_noguard(&self) { // SAFETY: `spin_lock` points to valid memory. - unsafe { rust_helper_spin_lock(self.spin_lock.get()) }; + unsafe { bindings::spin_lock(self.spin_lock.get()) }; } unsafe fn unlock(&self, _: &mut ()) { // SAFETY: The safety requirements of the function ensure that the spinlock is owned by the // caller. - unsafe { rust_helper_spin_unlock(self.spin_lock.get()) }; + unsafe { bindings::spin_unlock(self.spin_lock.get()) }; } fn locked_data(&self) -> &UnsafeCell { diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index dcf376b992ec47..7a2aff0e921911 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -4,20 +4,9 @@ //! //! C header: [`include/linux/sched.h`](../../../../include/linux/sched.h). -use crate::{bindings, c_types}; +use crate::bindings; use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref}; -extern "C" { - #[allow(improper_ctypes)] - fn rust_helper_signal_pending(t: *const bindings::task_struct) -> c_types::c_int; - #[allow(improper_ctypes)] - fn rust_helper_get_current() -> *mut bindings::task_struct; - #[allow(improper_ctypes)] - fn rust_helper_get_task_struct(t: *mut bindings::task_struct); - #[allow(improper_ctypes)] - fn rust_helper_put_task_struct(t: *mut bindings::task_struct); -} - /// Wraps the kernel's `struct task_struct`. /// /// # Invariants @@ -89,7 +78,7 @@ impl Task { /// Returns a task reference for the currently executing task/thread. pub fn current<'a>() -> TaskRef<'a> { // SAFETY: Just an FFI call. - let ptr = unsafe { rust_helper_get_current() }; + let ptr = unsafe { bindings::get_current() }; // SAFETY: If the current thread is still running, the current task is valid. Given // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread (where @@ -117,7 +106,7 @@ impl Task { /// Determines whether the given task has pending signals. pub fn signal_pending(&self) -> bool { // SAFETY: By the type invariant, we know that `self.ptr` is non-null and valid. - unsafe { rust_helper_signal_pending(self.ptr) != 0 } + unsafe { bindings::signal_pending(self.ptr) != 0 } } } @@ -132,7 +121,7 @@ impl Eq for Task {} impl Clone for Task { fn clone(&self) -> Self { // SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count. - unsafe { rust_helper_get_task_struct(self.ptr) }; + unsafe { bindings::get_task_struct(self.ptr) }; // INVARIANT: We incremented the reference count to account for the new `Task` being // created. @@ -145,7 +134,7 @@ impl Drop for Task { // INVARIANT: We may decrement the refcount to zero, but the `Task` is being dropped, so // this is not observable. // SAFETY: The type invariants guarantee that `Task::ptr` has a non-zero reference count. - unsafe { rust_helper_put_task_struct(self.ptr) }; + unsafe { bindings::put_task_struct(self.ptr) }; } } diff --git a/rust/kernel/user_ptr.rs b/rust/kernel/user_ptr.rs index 71ec659bcee30e..467ead639071c7 100644 --- a/rust/kernel/user_ptr.rs +++ b/rust/kernel/user_ptr.rs @@ -5,29 +5,13 @@ //! C header: [`include/linux/uaccess.h`](../../../../include/linux/uaccess.h) use crate::{ - c_types, + bindings, c_types, error::Error, io_buffer::{IoBufferReader, IoBufferWriter}, Result, }; use alloc::vec::Vec; -extern "C" { - fn rust_helper_copy_from_user( - to: *mut c_types::c_void, - from: *const c_types::c_void, - n: c_types::c_ulong, - ) -> c_types::c_ulong; - - fn rust_helper_copy_to_user( - to: *mut c_types::c_void, - from: *const c_types::c_void, - n: c_types::c_ulong, - ) -> c_types::c_ulong; - - fn rust_helper_clear_user(to: *mut c_types::c_void, n: c_types::c_ulong) -> c_types::c_ulong; -} - /// A reference to an area in userspace memory, which can be either /// read-only or read-write. /// @@ -130,7 +114,7 @@ impl IoBufferReader for UserSlicePtrReader { if len > self.1 || len > u32::MAX as usize { return Err(Error::EFAULT); } - let res = unsafe { rust_helper_copy_from_user(out as _, self.0, len as _) }; + let res = unsafe { bindings::copy_from_user(out as _, self.0, len as _) }; if res != 0 { return Err(Error::EFAULT); } @@ -162,7 +146,7 @@ impl IoBufferWriter for UserSlicePtrWriter { // SAFETY: The buffer will be validated by `clear_user`. We ensure that `len` is within // bounds in the check above. - let left = unsafe { rust_helper_clear_user(self.0, len as _) } as usize; + let left = unsafe { bindings::clear_user(self.0, len as _) } as usize; if left != 0 { ret = Err(Error::EFAULT); len -= left; @@ -177,7 +161,7 @@ impl IoBufferWriter for UserSlicePtrWriter { if len > self.1 || len > u32::MAX as usize { return Err(Error::EFAULT); } - let res = unsafe { rust_helper_copy_to_user(self.0, data as _, len as _) }; + let res = unsafe { bindings::copy_to_user(self.0, data as _, len as _) }; if res != 0 { return Err(Error::EFAULT); } From 4aa4dd5dec66d9c72ccf9255b565f47000db70df Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 24 Aug 2021 21:46:19 +0100 Subject: [PATCH 3/3] rust: compile readq/writeq only on 64-bit arch Signed-off-by: Gary Guo --- rust/kernel/io_mem.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/rust/kernel/io_mem.rs b/rust/kernel/io_mem.rs index c8277004dc0ba0..ddc23f637ebb3c 100644 --- a/rust/kernel/io_mem.rs +++ b/rust/kernel/io_mem.rs @@ -61,10 +61,11 @@ pub struct IoMem { } macro_rules! define_read { - ($name:ident, $try_name:ident, $type_name:ty) => { + ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => { /// Reads IO data from the given offset known, at compile time. /// /// If the offset is not known at compile time, the build will fail. + $(#[$attr])* pub fn $name(&self, offset: usize) -> $type_name { Self::check_offset::<$type_name>(offset); let ptr = self.ptr.wrapping_add(offset); @@ -77,6 +78,7 @@ macro_rules! define_read { /// Reads IO data from the given offset. /// /// It fails if/when the offset (plus the type size) is out of bounds. + $(#[$attr])* pub fn $try_name(&self, offset: usize) -> Result<$type_name> { if !Self::offset_ok::<$type_name>(offset) { return Err(Error::EINVAL); @@ -91,10 +93,11 @@ macro_rules! define_read { } macro_rules! define_write { - ($name:ident, $try_name:ident, $type_name:ty) => { + ($(#[$attr:meta])* $name:ident, $try_name:ident, $type_name:ty) => { /// Writes IO data to the given offset, known at compile time. /// /// If the offset is not known at compile time, the build will fail. + $(#[$attr])* pub fn $name(&self, value: $type_name, offset: usize) { Self::check_offset::<$type_name>(offset); let ptr = self.ptr.wrapping_add(offset); @@ -107,6 +110,7 @@ macro_rules! define_write { /// Writes IO data to the given offset. /// /// It fails if/when the offset (plus the type size) is out of bounds. + $(#[$attr])* pub fn $try_name(&self, value: $type_name, offset: usize) -> Result { if !Self::offset_ok::<$type_name>(offset) { return Err(Error::EINVAL); @@ -174,12 +178,22 @@ impl IoMem { define_read!(readb, try_readb, u8); define_read!(readw, try_readw, u16); define_read!(readl, try_readl, u32); - define_read!(readq, try_readq, u64); + define_read!( + #[cfg(CONFIG_64BIT)] + readq, + try_readq, + u64 + ); define_write!(writeb, try_writeb, u8); define_write!(writew, try_writew, u16); define_write!(writel, try_writel, u32); - define_write!(writeq, try_writeq, u64); + define_write!( + #[cfg(CONFIG_64BIT)] + writeq, + try_writeq, + u64 + ); } impl Drop for IoMem {