Skip to content

Commit

Permalink
rust: use custom FFI integer types
Browse files Browse the repository at this point in the history
Currently FFI integer types are defined in libcore. This commit creates
the `ffi` crate and asks bindgen to use that crate for FFI integer types
instead of `core::ffi`.

This commit is preparatory and no type changes are made in this commit
yet.

Signed-off-by: Gary Guo <gary@garyguo.net>
Link: https://lore.kernel.org/r/20240913213041.395655-4-gary@garyguo.net
[ Added `rustdoc`, `rusttest` and KUnit tests support. Rebased on top of
  `rust-next` (e.g. migrated more `core::ffi` cases). Reworded crate
  docs slightly and formatted. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
  • Loading branch information
nbdd0121 authored and ojeda committed Nov 10, 2024
1 parent 2fd6f55 commit d072acd
Show file tree
Hide file tree
Showing 23 changed files with 107 additions and 83 deletions.
39 changes: 26 additions & 13 deletions rust/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Where to place rustdoc generated documentation
rustdoc_output := $(objtree)/Documentation/output/rust/rustdoc

obj-$(CONFIG_RUST) += core.o compiler_builtins.o
obj-$(CONFIG_RUST) += core.o compiler_builtins.o ffi.o
always-$(CONFIG_RUST) += exports_core_generated.h

# Missing prototypes are expected in the helpers since these are exported
Expand Down Expand Up @@ -103,10 +103,13 @@ rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs FORCE
rustdoc-compiler_builtins: $(src)/compiler_builtins.rs rustdoc-core FORCE
+$(call if_changed,rustdoc)

rustdoc-kernel: private rustc_target_flags = \
rustdoc-ffi: $(src)/ffi.rs rustdoc-core FORCE
+$(call if_changed,rustdoc)

rustdoc-kernel: private rustc_target_flags = --extern ffi \
--extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
--extern bindings --extern uapi
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-ffi rustdoc-macros \
rustdoc-compiler_builtins $(obj)/libmacros.so \
$(obj)/bindings.o FORCE
+$(call if_changed,rustdoc)
Expand All @@ -124,23 +127,28 @@ quiet_cmd_rustc_test_library = RUSTC TL $<
rusttestlib-build_error: $(src)/build_error.rs FORCE
+$(call if_changed,rustc_test_library)

rusttestlib-ffi: $(src)/ffi.rs FORCE
+$(call if_changed,rustc_test_library)

rusttestlib-macros: private rustc_target_flags = --extern proc_macro
rusttestlib-macros: private rustc_test_library_proc = yes
rusttestlib-macros: $(src)/macros/lib.rs FORCE
+$(call if_changed,rustc_test_library)

rusttestlib-kernel: private rustc_target_flags = \
rusttestlib-kernel: private rustc_target_flags = --extern ffi \
--extern build_error --extern macros \
--extern bindings --extern uapi
rusttestlib-kernel: $(src)/kernel/lib.rs \
rusttestlib-bindings rusttestlib-uapi rusttestlib-build_error \
$(obj)/libmacros.so $(obj)/bindings.o FORCE
+$(call if_changed,rustc_test_library)

rusttestlib-bindings: $(src)/bindings/lib.rs FORCE
rusttestlib-bindings: private rustc_target_flags = --extern ffi
rusttestlib-bindings: $(src)/bindings/lib.rs rusttestlib-ffi FORCE
+$(call if_changed,rustc_test_library)

rusttestlib-uapi: $(src)/uapi/lib.rs FORCE
rusttestlib-uapi: private rustc_target_flags = --extern ffi
rusttestlib-uapi: $(src)/uapi/lib.rs rusttestlib-ffi FORCE
+$(call if_changed,rustc_test_library)

quiet_cmd_rustdoc_test = RUSTDOC T $<
Expand All @@ -160,7 +168,7 @@ 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 kernel \
-L$(objtree)/$(obj) --extern ffi --extern kernel \
--extern build_error --extern macros \
--extern bindings --extern uapi \
--no-run --crate-name kernel -Zunstable-options \
Expand Down Expand Up @@ -198,9 +206,9 @@ rusttest-macros: $(src)/macros/lib.rs \
+$(call if_changed,rustc_test)
+$(call if_changed,rustdoc_test)

rusttest-kernel: private rustc_target_flags = \
rusttest-kernel: private rustc_target_flags = --extern ffi \
--extern build_error --extern macros --extern bindings --extern uapi
rusttest-kernel: $(src)/kernel/lib.rs rusttestlib-kernel \
rusttest-kernel: $(src)/kernel/lib.rs rusttestlib-ffi rusttestlib-kernel \
rusttestlib-build_error rusttestlib-macros rusttestlib-bindings \
rusttestlib-uapi FORCE
+$(call if_changed,rustc_test)
Expand Down Expand Up @@ -273,7 +281,7 @@ bindgen_c_flags_final = $(bindgen_c_flags_lto) -fno-builtin -D__BINDGEN__
quiet_cmd_bindgen = BINDGEN $@
cmd_bindgen = \
$(BINDGEN) $< $(bindgen_target_flags) \
--use-core --with-derive-default --ctypes-prefix core::ffi --no-layout-tests \
--use-core --with-derive-default --ctypes-prefix ffi --no-layout-tests \
--no-debug '.*' --enable-function-attribute-detection \
-o $@ -- $(bindgen_c_flags_final) -DMODULE \
$(bindgen_target_cflags) $(bindgen_target_extra)
Expand Down Expand Up @@ -401,18 +409,23 @@ $(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE
$(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE
+$(call if_changed_rule,rustc_library)

$(obj)/ffi.o: $(src)/ffi.rs $(obj)/compiler_builtins.o FORCE
+$(call if_changed_rule,rustc_library)

$(obj)/bindings.o: private rustc_target_flags = --extern ffi
$(obj)/bindings.o: $(src)/bindings/lib.rs \
$(obj)/compiler_builtins.o \
$(obj)/ffi.o \
$(obj)/bindings/bindings_generated.rs \
$(obj)/bindings/bindings_helpers_generated.rs FORCE
+$(call if_changed_rule,rustc_library)

$(obj)/uapi.o: private rustc_target_flags = --extern ffi
$(obj)/uapi.o: $(src)/uapi/lib.rs \
$(obj)/compiler_builtins.o \
$(obj)/ffi.o \
$(obj)/uapi/uapi_generated.rs FORCE
+$(call if_changed_rule,rustc_library)

$(obj)/kernel.o: private rustc_target_flags = \
$(obj)/kernel.o: private rustc_target_flags = --extern ffi \
--extern build_error --extern macros --extern bindings --extern uapi
$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o \
$(obj)/libmacros.so $(obj)/bindings.o $(obj)/uapi.o FORCE
Expand Down
13 changes: 13 additions & 0 deletions rust/ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-2.0

//! Foreign function interface (FFI) types.
//!
//! This crate provides mapping from C primitive types to Rust ones.
//!
//! The Rust [`core`] crate provides [`core::ffi`], which maps integer types to the platform default
//! C ABI. The kernel does not use [`core::ffi`], so it can customise the mapping that deviates from
//! the platform default.

#![no_std]

pub use core::ffi::*;
2 changes: 1 addition & 1 deletion rust/kernel/alloc/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ fn aligned_size(new_layout: Layout) -> usize {
///
/// One of the following: `krealloc`, `vrealloc`, `kvrealloc`.
struct ReallocFunc(
unsafe extern "C" fn(*const core::ffi::c_void, usize, u32) -> *mut core::ffi::c_void,
unsafe extern "C" fn(*const crate::ffi::c_void, usize, u32) -> *mut crate::ffi::c_void,
);

impl ReallocFunc {
Expand Down
4 changes: 2 additions & 2 deletions rust/kernel/alloc/allocator_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ pub type KVmalloc = Kmalloc;

extern "C" {
#[link_name = "aligned_alloc"]
fn libc_aligned_alloc(align: usize, size: usize) -> *mut core::ffi::c_void;
fn libc_aligned_alloc(align: usize, size: usize) -> *mut crate::ffi::c_void;

#[link_name = "free"]
fn libc_free(ptr: *mut core::ffi::c_void);
fn libc_free(ptr: *mut crate::ffi::c_void);
}

// SAFETY:
Expand Down
12 changes: 6 additions & 6 deletions rust/kernel/alloc/kbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,17 +355,17 @@ where
{
type Borrowed<'a> = &'a T;

fn into_foreign(self) -> *const core::ffi::c_void {
fn into_foreign(self) -> *const crate::ffi::c_void {
Box::into_raw(self) as _
}

unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
unsafe { Box::from_raw(ptr as _) }
}

unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> &'a T {
// SAFETY: The safety requirements of this method ensure that the object remains alive and
// immutable for the duration of 'a.
unsafe { &*ptr.cast() }
Expand All @@ -378,18 +378,18 @@ where
{
type Borrowed<'a> = Pin<&'a T>;

fn into_foreign(self) -> *const core::ffi::c_void {
fn into_foreign(self) -> *const crate::ffi::c_void {
// SAFETY: We are still treating the box as pinned.
Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) as _
}

unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
unsafe { Pin::new_unchecked(Box::from_raw(ptr as _)) }
}

unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Pin<&'a T> {
unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Pin<&'a T> {
// SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for
Expand Down
18 changes: 9 additions & 9 deletions rust/kernel/block/mq/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl<T: Operations> OperationsVTable<T> {
unsafe extern "C" fn poll_callback(
_hctx: *mut bindings::blk_mq_hw_ctx,
_iob: *mut bindings::io_comp_batch,
) -> core::ffi::c_int {
) -> crate::ffi::c_int {
T::poll().into()
}

Expand All @@ -145,9 +145,9 @@ impl<T: Operations> OperationsVTable<T> {
/// for the same context.
unsafe extern "C" fn init_hctx_callback(
_hctx: *mut bindings::blk_mq_hw_ctx,
_tagset_data: *mut core::ffi::c_void,
_hctx_idx: core::ffi::c_uint,
) -> core::ffi::c_int {
_tagset_data: *mut crate::ffi::c_void,
_hctx_idx: crate::ffi::c_uint,
) -> crate::ffi::c_int {
from_result(|| Ok(0))
}

Expand All @@ -159,7 +159,7 @@ impl<T: Operations> OperationsVTable<T> {
/// This function may only be called by blk-mq C infrastructure.
unsafe extern "C" fn exit_hctx_callback(
_hctx: *mut bindings::blk_mq_hw_ctx,
_hctx_idx: core::ffi::c_uint,
_hctx_idx: crate::ffi::c_uint,
) {
}

Expand All @@ -176,9 +176,9 @@ impl<T: Operations> OperationsVTable<T> {
unsafe extern "C" fn init_request_callback(
_set: *mut bindings::blk_mq_tag_set,
rq: *mut bindings::request,
_hctx_idx: core::ffi::c_uint,
_numa_node: core::ffi::c_uint,
) -> core::ffi::c_int {
_hctx_idx: crate::ffi::c_uint,
_numa_node: crate::ffi::c_uint,
) -> crate::ffi::c_int {
from_result(|| {
// SAFETY: By the safety requirements of this function, `rq` points
// to a valid allocation.
Expand All @@ -203,7 +203,7 @@ impl<T: Operations> OperationsVTable<T> {
unsafe extern "C" fn exit_request_callback(
_set: *mut bindings::blk_mq_tag_set,
rq: *mut bindings::request,
_hctx_idx: core::ffi::c_uint,
_hctx_idx: crate::ffi::c_uint,
) {
// SAFETY: The tagset invariants guarantee that all requests are allocated with extra memory
// for the request data.
Expand Down
2 changes: 1 addition & 1 deletion rust/kernel/block/mq/raw_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl<'a> RawWriter<'a> {
}

pub(crate) fn from_array<const N: usize>(
a: &'a mut [core::ffi::c_char; N],
a: &'a mut [crate::ffi::c_char; N],
) -> Result<RawWriter<'a>> {
Self::new(
// SAFETY: the buffer of `a` is valid for read and write as `u8` for
Expand Down
2 changes: 1 addition & 1 deletion rust/kernel/block/mq/tag_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl<T: Operations> TagSet<T> {
queue_depth: num_tags,
cmd_size,
flags: bindings::BLK_MQ_F_SHOULD_MERGE,
driver_data: core::ptr::null_mut::<core::ffi::c_void>(),
driver_data: core::ptr::null_mut::<crate::ffi::c_void>(),
nr_maps: num_maps,
..tag_set
}
Expand Down
20 changes: 10 additions & 10 deletions rust/kernel/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl Error {
///
/// It is a bug to pass an out-of-range `errno`. `EINVAL` would
/// be returned in such a case.
pub fn from_errno(errno: core::ffi::c_int) -> Error {
pub fn from_errno(errno: crate::ffi::c_int) -> Error {
if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
// TODO: Make it a `WARN_ONCE` once available.
crate::pr_warn!(
Expand All @@ -119,7 +119,7 @@ impl Error {
/// Creates an [`Error`] from a kernel error code.
///
/// Returns [`None`] if `errno` is out-of-range.
const fn try_from_errno(errno: core::ffi::c_int) -> Option<Error> {
const fn try_from_errno(errno: crate::ffi::c_int) -> Option<Error> {
if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
return None;
}
Expand All @@ -133,15 +133,15 @@ impl Error {
/// # Safety
///
/// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
const unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error {
const unsafe fn from_errno_unchecked(errno: crate::ffi::c_int) -> Error {
// INVARIANT: The contract ensures the type invariant
// will hold.
// SAFETY: The caller guarantees `errno` is non-zero.
Error(unsafe { NonZeroI32::new_unchecked(errno) })
}

/// Returns the kernel error code.
pub fn to_errno(self) -> core::ffi::c_int {
pub fn to_errno(self) -> crate::ffi::c_int {
self.0.get()
}

Expand Down Expand Up @@ -259,7 +259,7 @@ pub type Result<T = (), E = Error> = core::result::Result<T, E>;

/// Converts an integer as returned by a C kernel function to an error if it's negative, and
/// `Ok(())` otherwise.
pub fn to_result(err: core::ffi::c_int) -> Result {
pub fn to_result(err: crate::ffi::c_int) -> Result {
if err < 0 {
Err(Error::from_errno(err))
} else {
Expand All @@ -282,15 +282,15 @@ pub fn to_result(err: core::ffi::c_int) -> Result {
/// fn devm_platform_ioremap_resource(
/// pdev: &mut PlatformDevice,
/// index: u32,
/// ) -> Result<*mut core::ffi::c_void> {
/// ) -> Result<*mut kernel::ffi::c_void> {
/// // SAFETY: `pdev` points to a valid platform device. There are no safety requirements
/// // on `index`.
/// from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) })
/// }
/// ```
pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
// CAST: Casting a pointer to `*const core::ffi::c_void` is always valid.
let const_ptr: *const core::ffi::c_void = ptr.cast();
// CAST: Casting a pointer to `*const crate::ffi::c_void` is always valid.
let const_ptr: *const crate::ffi::c_void = ptr.cast();
// SAFETY: The FFI function does not deref the pointer.
if unsafe { bindings::IS_ERR(const_ptr) } {
// SAFETY: The FFI function does not deref the pointer.
Expand All @@ -306,7 +306,7 @@ pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
//
// SAFETY: `IS_ERR()` ensures `err` is a
// negative value greater-or-equal to `-bindings::MAX_ERRNO`.
return Err(unsafe { Error::from_errno_unchecked(err as core::ffi::c_int) });
return Err(unsafe { Error::from_errno_unchecked(err as crate::ffi::c_int) });
}
Ok(ptr)
}
Expand All @@ -326,7 +326,7 @@ pub fn from_err_ptr<T>(ptr: *mut T) -> Result<*mut T> {
/// # use kernel::bindings;
/// unsafe extern "C" fn probe_callback(
/// pdev: *mut bindings::platform_device,
/// ) -> core::ffi::c_int {
/// ) -> kernel::ffi::c_int {
/// from_result(|| {
/// let ptr = devm_alloc(pdev)?;
/// bindings::platform_set_drvdata(pdev, ptr);
Expand Down
2 changes: 1 addition & 1 deletion rust/kernel/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
//! # }
//! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround.
//! # trait FromErrno {
//! # fn from_errno(errno: core::ffi::c_int) -> Error {
//! # fn from_errno(errno: kernel::ffi::c_int) -> Error {
//! # // Dummy error that can be constructed outside the `kernel` crate.
//! # Error::from(core::fmt::Error)
//! # }
Expand Down
2 changes: 2 additions & 0 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ compile_error!("Missing kernel configuration for conditional compilation");
// Allow proc-macros to refer to `::kernel` inside the `kernel` crate (this crate).
extern crate self as kernel;

pub use ffi;

pub mod alloc;
#[cfg(CONFIG_BLOCK)]
pub mod block;
Expand Down
Loading

0 comments on commit d072acd

Please sign in to comment.