summaryrefslogtreecommitdiff
path: root/rust/kernel/transmute.rs
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2025-09-17 16:09:24 +1000
committerDave Airlie <airlied@redhat.com>2025-09-17 16:13:49 +1000
commit6f17ab9a63e670bd62a287f95e3982f99eafd77e (patch)
tree22a564695db44faa7428d309d2ae4570d613268f /rust/kernel/transmute.rs
parent5770495279d79514989b00fe9ef0ff487bf2e54e (diff)
parent299eb32863e584cfff7c6b667c3e92ae7d4d2bf9 (diff)
Merge tag 'drm-rust-next-2025-09-16' of https://gitlab.freedesktop.org/drm/rust/kernel into drm-next
DRM Rust changes for v6.18 Alloc - Add BorrowedPage type and AsPageIter trait - Implement Vmalloc::to_page() and VmallocPageIter - Implement AsPageIter for VBox and VVec DMA & Scatterlist - Add dma::DataDirection and type alias for dma_addr_t - Abstraction for struct scatterlist and struct sg_table DRM - In the DRM GEM module, simplify overall use of generics, add DriverFile type alias and drop Object::SIZE. Nova (Core) - Various register!() macro improvements (paving the way for lifting it to common driver infrastructure) - Minor VBios fixes and refactoring - Minor firmware request refactoring - Advance firmware boot stages; process Booter and patch its signature, process GSP and GSP bootloader - Switch development fimrware version to r570.144 - Add basic firmware bindings for r570.144 - Move GSP boot code to its own module - Clean up and take advantage of pin-init features to store most of the driver's private data within a single allocation - Update ARef import from sync::aref - Add website to MAINTAINERS entry Nova (DRM) - Update ARef import from sync::aref - Add website to MAINTAINERS entry Pin-Init - Merge pin-init PR from Benno - `#[pin_data]` now generates a `*Projection` struct similar to the `pin-project` crate. - Add initializer code blocks to `[try_][pin_]init!` macros: make initializer macros accept any number of `_: {/* arbitrary code */},` & make them run the code at that point. - Make the `[try_][pin_]init!` macros expose initialized fields via a `let` binding as `&mut T` or `Pin<&mut T>` for later fields. Rust - Various methods for AsBytes and FromBytes traits Tyr - Initial Rust driver skeleton for ARM Mali GPUs. - It can power up the GPU, query for GPU metatdata through MMIO and provide the metadata to userspace via DRM device IOCTL (struct drm_panthor_dev_query). Signed-off-by: Dave Airlie <airlied@redhat.com> From: "Danilo Krummrich" <dakr@kernel.org> Link: https://lore.kernel.org/r/DCUC4SY6SRBD.1ZLHAIQZOC6KG@kernel.org
Diffstat (limited to 'rust/kernel/transmute.rs')
-rw-r--r--rust/kernel/transmute.rs114
1 files changed, 112 insertions, 2 deletions
diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs
index 1c7d43771a37..cfc37d81adf2 100644
--- a/rust/kernel/transmute.rs
+++ b/rust/kernel/transmute.rs
@@ -2,6 +2,8 @@
//! Traits for transmuting types.
+use core::mem::size_of;
+
/// Types for which any bit pattern is valid.
///
/// Not all types are valid for all values. For example, a `bool` must be either zero or one, so
@@ -9,10 +11,93 @@
///
/// It's okay for the type to have padding, as initializing those bytes has no effect.
///
+/// # Examples
+///
+/// ```
+/// use kernel::transmute::FromBytes;
+///
+/// # fn test() -> Option<()> {
+/// let raw = [1, 2, 3, 4];
+///
+/// let result = u32::from_bytes(&raw)?;
+///
+/// #[cfg(target_endian = "little")]
+/// assert_eq!(*result, 0x4030201);
+///
+/// #[cfg(target_endian = "big")]
+/// assert_eq!(*result, 0x1020304);
+///
+/// # Some(()) }
+/// # test().ok_or(EINVAL)?;
+/// # Ok::<(), Error>(())
+/// ```
+///
/// # Safety
///
/// All bit-patterns must be valid for this type. This type must not have interior mutability.
-pub unsafe trait FromBytes {}
+pub unsafe trait FromBytes {
+ /// Converts a slice of bytes to a reference to `Self`.
+ ///
+ /// Succeeds if the reference is properly aligned, and the size of `bytes` is equal to that of
+ /// `T` and different from zero.
+ ///
+ /// Otherwise, returns [`None`].
+ fn from_bytes(bytes: &[u8]) -> Option<&Self>
+ where
+ Self: Sized,
+ {
+ let slice_ptr = bytes.as_ptr().cast::<Self>();
+ let size = size_of::<Self>();
+
+ #[allow(clippy::incompatible_msrv)]
+ if bytes.len() == size && slice_ptr.is_aligned() {
+ // SAFETY: Size and alignment were just checked.
+ unsafe { Some(&*slice_ptr) }
+ } else {
+ None
+ }
+ }
+
+ /// Converts a mutable slice of bytes to a reference to `Self`.
+ ///
+ /// Succeeds if the reference is properly aligned, and the size of `bytes` is equal to that of
+ /// `T` and different from zero.
+ ///
+ /// Otherwise, returns [`None`].
+ fn from_bytes_mut(bytes: &mut [u8]) -> Option<&mut Self>
+ where
+ Self: AsBytes + Sized,
+ {
+ let slice_ptr = bytes.as_mut_ptr().cast::<Self>();
+ let size = size_of::<Self>();
+
+ #[allow(clippy::incompatible_msrv)]
+ if bytes.len() == size && slice_ptr.is_aligned() {
+ // SAFETY: Size and alignment were just checked.
+ unsafe { Some(&mut *slice_ptr) }
+ } else {
+ None
+ }
+ }
+
+ /// Creates an owned instance of `Self` by copying `bytes`.
+ ///
+ /// Unlike [`FromBytes::from_bytes`], which requires aligned input, this method can be used on
+ /// non-aligned data at the cost of a copy.
+ fn from_bytes_copy(bytes: &[u8]) -> Option<Self>
+ where
+ Self: Sized,
+ {
+ if bytes.len() == size_of::<Self>() {
+ // SAFETY: we just verified that `bytes` has the same size as `Self`, and per the
+ // invariants of `FromBytes`, any byte sequence of the correct length is a valid value
+ // for `Self`.
+ Some(unsafe { core::ptr::read_unaligned(bytes.as_ptr().cast::<Self>()) })
+ } else {
+ None
+ }
+ }
+}
macro_rules! impl_frombytes {
($($({$($generics:tt)*})? $t:ty, )*) => {
@@ -47,7 +132,32 @@ impl_frombytes! {
///
/// Values of this type may not contain any uninitialized bytes. This type must not have interior
/// mutability.
-pub unsafe trait AsBytes {}
+pub unsafe trait AsBytes {
+ /// Returns `self` as a slice of bytes.
+ fn as_bytes(&self) -> &[u8] {
+ // CAST: `Self` implements `AsBytes` thus all bytes of `self` are initialized.
+ let data = core::ptr::from_ref(self).cast::<u8>();
+ let len = core::mem::size_of_val(self);
+
+ // SAFETY: `data` is non-null and valid for reads of `len * sizeof::<u8>()` bytes.
+ unsafe { core::slice::from_raw_parts(data, len) }
+ }
+
+ /// Returns `self` as a mutable slice of bytes.
+ fn as_bytes_mut(&mut self) -> &mut [u8]
+ where
+ Self: FromBytes,
+ {
+ // CAST: `Self` implements both `AsBytes` and `FromBytes` thus making `Self`
+ // bi-directionally transmutable to `[u8; size_of_val(self)]`.
+ let data = core::ptr::from_mut(self).cast::<u8>();
+ let len = core::mem::size_of_val(self);
+
+ // SAFETY: `data` is non-null and valid for read and writes of `len * sizeof::<u8>()`
+ // bytes.
+ unsafe { core::slice::from_raw_parts_mut(data, len) }
+ }
+}
macro_rules! impl_asbytes {
($($({$($generics:tt)*})? $t:ty, )*) => {