mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-04-13 09:59:31 +00:00
rust: map long
to isize
and char
to u8
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@garyguo.net> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240913213041.395655-5-gary@garyguo.net [ Moved `uaccess` changes from the next commit, since they were irrefutable patterns that Rust >= 1.82.0 warns about. Reworded slightly and reformatted a few documentation comments. Rebased on top of `rust-next`. Added the removal of two casts to avoid Clippy warnings. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
27c7518e7f
commit
1bae8729e5
5 changed files with 47 additions and 28 deletions
37
rust/ffi.rs
37
rust/ffi.rs
|
@ -10,4 +10,39 @@
|
||||||
|
|
||||||
#![no_std]
|
#![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 `core`.
|
||||||
|
const _: () = assert!(
|
||||||
|
core::mem::size_of::<$name>() == core::mem::size_of::<core::ffi::$name>()
|
||||||
|
);
|
||||||
|
)*}
|
||||||
|
}
|
||||||
|
|
||||||
|
alias! {
|
||||||
|
// `core::ffi::c_char` is either `i8` or `u8` depending on architecture. In the 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 the 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;
|
||||||
|
|
|
@ -153,11 +153,8 @@ impl Error {
|
||||||
|
|
||||||
/// Returns the error encoded as a pointer.
|
/// Returns the error encoded as a pointer.
|
||||||
pub fn to_ptr<T>(self) -> *mut T {
|
pub 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.
|
// SAFETY: `self.0` is a valid error due to its invariant.
|
||||||
unsafe {
|
unsafe { bindings::ERR_PTR(self.0.get() as _) as *mut _ }
|
||||||
bindings::ERR_PTR(self.0.get().into()) as *mut _
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a string representing the error, if one exists.
|
/// Returns a string representing the error, if one exists.
|
||||||
|
|
|
@ -12,7 +12,7 @@ use core::ptr::NonNull;
|
||||||
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
|
/// One of the following: `bindings::request_firmware`, `bindings::firmware_request_nowarn`,
|
||||||
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
|
/// `bindings::firmware_request_platform`, `bindings::request_firmware_direct`.
|
||||||
struct FwFunc(
|
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 {
|
impl FwFunc {
|
||||||
|
|
|
@ -225,7 +225,7 @@ unsafe extern "C" fn fops_ioctl<T: MiscDevice>(
|
||||||
// SAFETY: Ioctl calls can borrow the private data of the file.
|
// SAFETY: Ioctl calls can borrow the private data of the file.
|
||||||
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
|
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
|
||||||
|
|
||||||
match T::ioctl(device, cmd, arg as usize) {
|
match T::ioctl(device, cmd, arg) {
|
||||||
Ok(ret) => ret as c_long,
|
Ok(ret) => ret as c_long,
|
||||||
Err(err) => err.to_errno() as c_long,
|
Err(err) => err.to_errno() as c_long,
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ unsafe extern "C" fn fops_compat_ioctl<T: MiscDevice>(
|
||||||
// SAFETY: Ioctl calls can borrow the private data of the file.
|
// SAFETY: Ioctl calls can borrow the private data of the file.
|
||||||
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
|
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
|
||||||
|
|
||||||
match T::compat_ioctl(device, cmd, arg as usize) {
|
match T::compat_ioctl(device, cmd, arg) {
|
||||||
Ok(ret) => ret as c_long,
|
Ok(ret) => ret as c_long,
|
||||||
Err(err) => err.to_errno() as c_long,
|
Err(err) => err.to_errno() as c_long,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
alloc::Flags,
|
alloc::Flags,
|
||||||
bindings,
|
bindings,
|
||||||
error::Result,
|
error::Result,
|
||||||
ffi::{c_ulong, c_void},
|
ffi::c_void,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
transmute::{AsBytes, FromBytes},
|
transmute::{AsBytes, FromBytes},
|
||||||
};
|
};
|
||||||
|
@ -224,13 +224,9 @@ impl UserSliceReader {
|
||||||
if len > self.length {
|
if len > self.length {
|
||||||
return Err(EFAULT);
|
return Err(EFAULT);
|
||||||
}
|
}
|
||||||
let Ok(len_ulong) = c_ulong::try_from(len) else {
|
// SAFETY: `out_ptr` points into a mutable slice of length `len`, so we may write
|
||||||
return Err(EFAULT);
|
|
||||||
};
|
|
||||||
// SAFETY: `out_ptr` points into a mutable slice of length `len_ulong`, so we may write
|
|
||||||
// that many bytes to it.
|
// that many bytes to it.
|
||||||
let res =
|
let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len) };
|
||||||
unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len_ulong) };
|
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
return Err(EFAULT);
|
return Err(EFAULT);
|
||||||
}
|
}
|
||||||
|
@ -259,9 +255,6 @@ impl UserSliceReader {
|
||||||
if len > self.length {
|
if len > self.length {
|
||||||
return Err(EFAULT);
|
return Err(EFAULT);
|
||||||
}
|
}
|
||||||
let Ok(len_ulong) = c_ulong::try_from(len) else {
|
|
||||||
return Err(EFAULT);
|
|
||||||
};
|
|
||||||
let mut out: MaybeUninit<T> = MaybeUninit::uninit();
|
let mut out: MaybeUninit<T> = MaybeUninit::uninit();
|
||||||
// SAFETY: The local variable `out` is valid for writing `size_of::<T>()` bytes.
|
// SAFETY: The local variable `out` is valid for writing `size_of::<T>()` bytes.
|
||||||
//
|
//
|
||||||
|
@ -272,7 +265,7 @@ impl UserSliceReader {
|
||||||
bindings::_copy_from_user(
|
bindings::_copy_from_user(
|
||||||
out.as_mut_ptr().cast::<c_void>(),
|
out.as_mut_ptr().cast::<c_void>(),
|
||||||
self.ptr as *const c_void,
|
self.ptr as *const c_void,
|
||||||
len_ulong,
|
len,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
|
@ -335,12 +328,9 @@ impl UserSliceWriter {
|
||||||
if len > self.length {
|
if len > self.length {
|
||||||
return Err(EFAULT);
|
return Err(EFAULT);
|
||||||
}
|
}
|
||||||
let Ok(len_ulong) = c_ulong::try_from(len) else {
|
// SAFETY: `data_ptr` points into an immutable slice of length `len`, so we may read
|
||||||
return Err(EFAULT);
|
|
||||||
};
|
|
||||||
// SAFETY: `data_ptr` points into an immutable slice of length `len_ulong`, so we may read
|
|
||||||
// that many bytes from it.
|
// that many bytes from it.
|
||||||
let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len_ulong) };
|
let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len) };
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
return Err(EFAULT);
|
return Err(EFAULT);
|
||||||
}
|
}
|
||||||
|
@ -359,9 +349,6 @@ impl UserSliceWriter {
|
||||||
if len > self.length {
|
if len > self.length {
|
||||||
return Err(EFAULT);
|
return Err(EFAULT);
|
||||||
}
|
}
|
||||||
let Ok(len_ulong) = c_ulong::try_from(len) else {
|
|
||||||
return Err(EFAULT);
|
|
||||||
};
|
|
||||||
// SAFETY: The reference points to a value of type `T`, so it is valid for reading
|
// SAFETY: The reference points to a value of type `T`, so it is valid for reading
|
||||||
// `size_of::<T>()` bytes.
|
// `size_of::<T>()` bytes.
|
||||||
//
|
//
|
||||||
|
@ -372,7 +359,7 @@ impl UserSliceWriter {
|
||||||
bindings::_copy_to_user(
|
bindings::_copy_to_user(
|
||||||
self.ptr as *mut c_void,
|
self.ptr as *mut c_void,
|
||||||
(value as *const T).cast::<c_void>(),
|
(value as *const T).cast::<c_void>(),
|
||||||
len_ulong,
|
len,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue