diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index ef2d490965ba..bcf248f69252 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -931,7 +931,7 @@ fn draw_all(&mut self, data: impl Iterator) { /// They must remain valid for the duration of the function call. #[no_mangle] pub unsafe extern "C" fn drm_panic_qr_generate( - url: *const i8, + url: *const kernel::ffi::c_char, data: *mut u8, data_len: usize, data_size: usize, diff --git a/rust/ffi.rs b/rust/ffi.rs index be153c4d551b..584f75b49862 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 `core`. + const _: () = assert!( + core::mem::size_of::<$name>() == core::mem::size_of::() + ); + )*} +} + +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; diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index 9ce414361c2c..19e227351918 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -427,13 +427,23 @@ fn deref_mut(&mut self) -> &mut T { } } +impl fmt::Display for Box +where + T: ?Sized + fmt::Display, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ::fmt(&**self, f) + } +} + impl fmt::Debug for Box where T: ?Sized + fmt::Debug, A: Allocator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) + ::fmt(&**self, f) } } diff --git a/rust/kernel/block/mq/gen_disk.rs b/rust/kernel/block/mq/gen_disk.rs index 798c4ae0bded..14806e1997fd 100644 --- a/rust/kernel/block/mq/gen_disk.rs +++ b/rust/kernel/block/mq/gen_disk.rs @@ -174,9 +174,9 @@ pub fn build( /// /// # Invariants /// -/// - `gendisk` must always point to an initialized and valid `struct gendisk`. -/// - `gendisk` was added to the VFS through a call to -/// `bindings::device_add_disk`. +/// - `gendisk` must always point to an initialized and valid `struct gendisk`. +/// - `gendisk` was added to the VFS through a call to +/// `bindings::device_add_disk`. pub struct GenDisk { _tagset: Arc>, gendisk: *mut bindings::gendisk, diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index c926e0c2b852..d5e6a19ff6b7 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -173,10 +173,10 @@ unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) { #[cfg(CONFIG_PRINTK)] unsafe { bindings::_dev_printk( - klevel as *const _ as *const core::ffi::c_char, + klevel as *const _ as *const crate::ffi::c_char, self.as_raw(), c_str!("%pA").as_char_ptr(), - &msg as *const _ as *const core::ffi::c_void, + &msg as *const _ as *const crate::ffi::c_void, ) }; } diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 52c502432447..914e8dec1abd 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -101,19 +101,16 @@ 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: crate::ffi::c_int) -> Error { - if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 { + if let Some(error) = Self::try_from_errno(errno) { + error + } else { // TODO: Make it a `WARN_ONCE` once available. crate::pr_warn!( "attempted to create `Error` with out of range `errno`: {}", errno ); - return code::EINVAL; + code::EINVAL } - - // INVARIANT: The check above ensures the type invariant - // will hold. - // SAFETY: `errno` is checked above to be in a valid range. - unsafe { Error::from_errno_unchecked(errno) } } /// Creates an [`Error`] from a kernel error code. @@ -153,11 +150,8 @@ pub(crate) fn to_blk_status(self) -> bindings::blk_status_t { /// Returns the error encoded as a pointer. pub fn to_ptr(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.get().into()) as *mut _ - } + unsafe { bindings::ERR_PTR(self.0.get() 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 13a374a5cdb7..c5162fdc95ff 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 { diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index ebc82e7dfc80..2e2a98e2f994 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -12,18 +12,14 @@ bindings, device::Device, error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR}, + ffi::{c_int, c_long, c_uint, c_ulong}, fs::File, prelude::*, seq_file::SeqFile, str::CStr, types::{ForeignOwnable, Opaque}, }; -use core::{ - ffi::{c_int, c_long, c_uint, c_ulong}, - marker::PhantomData, - mem::MaybeUninit, - pin::Pin, -}; +use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin}; /// Options for creating a misc device. #[derive(Copy, Clone)] @@ -279,7 +275,7 @@ impl VtableHelper { // * There is no active fdget_pos region on the file on this thread. let file = unsafe { File::from_raw_file(file) }; - match T::ioctl(device, file, cmd, arg as usize) { + match T::ioctl(device, file, cmd, arg) { Ok(ret) => ret as c_long, Err(err) => err.to_errno() as c_long, } @@ -304,7 +300,7 @@ impl VtableHelper { // * There is no active fdget_pos region on the file on this thread. let file = unsafe { File::from_raw_file(file) }; - match T::compat_ioctl(device, file, cmd, arg as usize) { + match T::compat_ioctl(device, file, cmd, arg) { Ok(ret) => ret as c_long, Err(err) => err.to_errno() as c_long, } diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index a28077a7cb30..b19ee490be58 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -107,7 +107,7 @@ pub unsafe fn call_printk( // SAFETY: TODO. unsafe { bindings::_printk( - format_string.as_ptr() as _, + format_string.as_ptr(), module_name.as_ptr(), &args as *const _ as *const c_void, ); @@ -128,7 +128,7 @@ pub fn call_printk_cont(args: fmt::Arguments<'_>) { #[cfg(CONFIG_PRINTK)] unsafe { bindings::_printk( - format_strings::CONT.as_ptr() as _, + format_strings::CONT.as_ptr(), &args as *const _ as *const c_void, ); } diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs index 6ca29d576d02..04947c672979 100644 --- a/rust/kernel/seq_file.rs +++ b/rust/kernel/seq_file.rs @@ -36,7 +36,7 @@ pub fn call_printf(&self, args: core::fmt::Arguments<'_>) { bindings::seq_printf( self.inner.get(), c_str!("%pA").as_char_ptr(), - &args as *const _ as *const core::ffi::c_void, + &args as *const _ as *const crate::ffi::c_void, ); } } diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index d04c12a1426d..0f2765463dc8 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -189,7 +189,7 @@ pub unsafe fn from_char_ptr<'a>(ptr: *const crate::ffi::c_char) -> &'a Self { // to a `NUL`-terminated C string. let len = unsafe { bindings::strlen(ptr) } + 1; // SAFETY: Lifetime guaranteed by the safety precondition. - let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len as _) }; + let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len) }; // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`. // As we have added 1 to `len`, the last byte is known to be `NUL`. unsafe { Self::from_bytes_with_nul_unchecked(bytes) } @@ -248,7 +248,7 @@ pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr { /// Returns a C pointer to the string. #[inline] pub const fn as_char_ptr(&self) -> *const crate::ffi::c_char { - self.0.as_ptr() as _ + self.0.as_ptr() } /// Convert the string to a byte slice without the trailing `NUL` byte. @@ -838,7 +838,7 @@ pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result { // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size` // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator) // so `f.bytes_written() - 1` doesn't underflow. - let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) }; + let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, f.bytes_written() - 1) }; if !ptr.is_null() { return Err(EINVAL); } diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index fa4509406ee9..9f0b04400e8e 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -127,6 +127,14 @@ /// ``` pub struct Arc { ptr: NonNull>, + // NB: this informs dropck that objects of type `ArcInner` may be used in ` as + // Drop>::drop`. Note that dropck already assumes that objects of type `T` may be used in + // ` as Drop>::drop` and the distinction between `T` and `ArcInner` is not presently + // meaningful with respect to dropck - but this may change in the future so this is left here + // out of an abundance of caution. + // + // See https://doc.rust-lang.org/nomicon/phantom-data.html#generic-parameters-and-drop-checking + // for more detail on the semantics of dropck in the presence of `PhantomData`. _p: PhantomData>, } diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index 05b0b8d13b10..cc044924867b 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -8,7 +8,7 @@ alloc::Flags, bindings, error::Result, - ffi::{c_ulong, c_void}, + ffi::c_void, prelude::*, transmute::{AsBytes, FromBytes}, }; @@ -224,13 +224,9 @@ pub fn read_raw(&mut self, out: &mut [MaybeUninit]) -> Result { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; - // SAFETY: `out_ptr` points into a mutable slice of length `len_ulong`, so we may write + // SAFETY: `out_ptr` points into a mutable slice of length `len`, so we may write // that many bytes to it. - let res = - unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len_ulong) }; + let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len) }; if res != 0 { return Err(EFAULT); } @@ -259,9 +255,6 @@ pub fn read(&mut self) -> Result { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; let mut out: MaybeUninit = MaybeUninit::uninit(); // SAFETY: The local variable `out` is valid for writing `size_of::()` bytes. // @@ -272,7 +265,7 @@ pub fn read(&mut self) -> Result { bindings::_copy_from_user( out.as_mut_ptr().cast::(), self.ptr as *const c_void, - len_ulong, + len, ) }; if res != 0 { @@ -335,12 +328,9 @@ pub fn write_slice(&mut self, data: &[u8]) -> Result { if len > self.length { return Err(EFAULT); } - let Ok(len_ulong) = c_ulong::try_from(len) else { - return Err(EFAULT); - }; - // SAFETY: `data_ptr` points into an immutable slice of length `len_ulong`, so we may read + // SAFETY: `data_ptr` points into an immutable slice of length `len`, so we may read // 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 { return Err(EFAULT); } @@ -359,9 +349,6 @@ pub fn write(&mut self, value: &T) -> Result { if len > self.length { 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 // `size_of::()` bytes. // @@ -372,7 +359,7 @@ pub fn write(&mut self, value: &T) -> Result { bindings::_copy_to_user( self.ptr as *mut c_void, (value as *const T).cast::(), - len_ulong, + len, ) }; if res != 0 { diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index fd3e97192ed8..0cd100d2aefb 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -69,6 +69,7 @@ //! fn print_later(val: Arc) { //! let _ = workqueue::system().enqueue(val); //! } +//! # print_later(MyStruct::new(42).unwrap()); //! ``` //! //! The following example shows how multiple `work_struct` fields can be used: @@ -126,6 +127,8 @@ //! fn print_2_later(val: Arc) { //! let _ = workqueue::system().enqueue::, 2>(val); //! } +//! # print_1_later(MyStruct::new(24, 25).unwrap()); +//! # print_2_later(MyStruct::new(41, 42).unwrap()); //! ``` //! //! C header: [`include/linux/workqueue.h`](srctree/include/linux/workqueue.h) diff --git a/samples/rust/rust_print_main.rs b/samples/rust/rust_print_main.rs index aed90a6feecf..7935b4772ec6 100644 --- a/samples/rust/rust_print_main.rs +++ b/samples/rust/rust_print_main.rs @@ -83,7 +83,7 @@ fn drop(&mut self) { } mod trace { - use core::ffi::c_int; + use kernel::ffi::c_int; kernel::declare_trace! { /// # Safety