[PATCH 4/5] rust: map `long` to `isize` and `char` to `u8`

From: Gary Guo
Date: Fri Sep 13 2024 - 17:33:49 EST


The following FFI types are replaced compared to `core::ffi`:

1. `char` type is now always mapped to `u8`, since kernel uses
`-funsigned-char` on the C code. `core::ffi` maps it to platform
default ABI, which can be either signed or unsigned.

2. `long` is now always mapped to `isize`. It's very common in the
kernel to use `long` to represent a pointer-sized integer, and in
fact `intptr_t` is a typedef of `long` in the kernel. Enforce this
mapping rather than mapping to `i32/i64` depending on platform can
save us a lot of unnecessary casts.

Signed-off-by: Gary Guo <gary@xxxxxxxxxxx>
---
rust/ffi.rs | 37 ++++++++++++++++++++++++++++++++++++-
rust/kernel/error.rs | 5 +----
rust/kernel/firmware.rs | 2 +-
3 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/rust/ffi.rs b/rust/ffi.rs
index 1894a511ee171..814d10106b5a8 100644
--- a/rust/ffi.rs
+++ b/rust/ffi.rs
@@ -10,4 +10,39 @@

#![no_std]

-pub use core::ffi::*;
+macro_rules! alias {
+ ($($name:ident = $ty:ty;)*) => {$(
+ #[allow(non_camel_case_types, missing_docs)]
+ pub type $name = $ty;
+
+ // Check size compatibility with libcore.
+ const _: () = assert!(
+ core::mem::size_of::<$name>() == core::mem::size_of::<core::ffi::$name>()
+ );
+ )*}
+}
+
+alias! {
+ // `core::ffi::c_char` is either i8/u8 depending on architecture. In kernel, we use
+ // `-funsigned-char` so it's always mapped to u8.
+ c_char = u8;
+
+ c_schar = i8;
+ c_uchar = u8;
+
+ c_short = i16;
+ c_ushort = u16;
+
+ c_int = i32;
+ c_uint = u32;
+
+ // In kernel, `intptr_t` is defined to be `long` in all platforms, so we can map the type to
+ // `isize`.
+ c_long = isize;
+ c_ulong = usize;
+
+ c_longlong = i64;
+ c_ulonglong = u64;
+}
+
+pub use core::ffi::c_void;
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 1090a13c2bd17..b9ad9ff25cddb 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -135,11 +135,8 @@ pub(crate) fn to_blk_status(self) -> bindings::blk_status_t {
/// Returns the error encoded as a pointer.
#[allow(dead_code)]
pub(crate) fn to_ptr<T>(self) -> *mut T {
- #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))]
// SAFETY: `self.0` is a valid error due to its invariant.
- unsafe {
- bindings::ERR_PTR(self.0.into()) as *mut _
- }
+ unsafe { bindings::ERR_PTR(self.0 as _) as *mut _ }
}

/// Returns a string representing the error, if one exists.
diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs
index dee5b4b18aec4..6f77945016579 100644
--- a/rust/kernel/firmware.rs
+++ b/rust/kernel/firmware.rs
@@ -12,7 +12,7 @@
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
struct FwFunc(
- unsafe extern "C" fn(*mut *const bindings::firmware, *const i8, *mut bindings::device) -> i32,
+ unsafe extern "C" fn(*mut *const bindings::firmware, *const u8, *mut bindings::device) -> i32,
);

impl FwFunc {
--
2.44.1