diff options
-rw-r--r-- | rust/kernel/device.rs | 44 | ||||
-rw-r--r-- | rust/kernel/pci.rs | 16 | ||||
-rw-r--r-- | rust/kernel/platform.rs | 17 |
3 files changed, 50 insertions, 27 deletions
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 21b343a1dc4d..9520e054996d 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -235,6 +235,50 @@ mod private { impl DeviceContext for Core {} impl DeviceContext for Normal {} +/// # Safety +/// +/// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the +/// generic argument of `$device`. +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_device_context_deref { + (unsafe { $device:ident, $src:ty => $dst:ty }) => { + impl ::core::ops::Deref for $device<$src> { + type Target = $device<$dst>; + + fn deref(&self) -> &Self::Target { + let ptr: *const Self = self; + + // CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the + // safety requirement of the macro. + let ptr = ptr.cast::<Self::Target>(); + + // SAFETY: `ptr` was derived from `&self`. + unsafe { &*ptr } + } + } + }; +} + +/// Implement [`core::ops::Deref`] traits for allowed [`DeviceContext`] conversions of a (bus +/// specific) device. +/// +/// # Safety +/// +/// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the +/// generic argument of `$device`. +#[macro_export] +macro_rules! impl_device_context_deref { + (unsafe { $device:ident }) => { + // SAFETY: This macro has the exact same safety requirement as + // `__impl_device_context_deref!`. + ::kernel::__impl_device_context_deref!(unsafe { + $device, + $crate::device::Core => $crate::device::Normal + }); + }; +} + #[doc(hidden)] #[macro_export] macro_rules! dev_printk { diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index c97d6d470b28..8474608e7a90 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -422,19 +422,9 @@ impl Device<device::Core> { } } -impl Deref for Device<device::Core> { - type Target = Device; - - fn deref(&self) -> &Self::Target { - let ptr: *const Self = self; - - // CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::pci_dev>`. - let ptr = ptr.cast::<Device>(); - - // SAFETY: `ptr` was derived from `&self`. - unsafe { &*ptr } - } -} +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); impl From<&Device<device::Core>> for ARef<Device> { fn from(dev: &Device<device::Core>) -> Self { diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 4917cb34e2fe..22590bdff7bb 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -16,7 +16,6 @@ use crate::{ use core::{ marker::PhantomData, - ops::Deref, ptr::{addr_of_mut, NonNull}, }; @@ -190,19 +189,9 @@ impl Device { } } -impl Deref for Device<device::Core> { - type Target = Device; - - fn deref(&self) -> &Self::Target { - let ptr: *const Self = self; - - // CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::platform_device>`. - let ptr = ptr.cast::<Device>(); - - // SAFETY: `ptr` was derived from `&self`. - unsafe { &*ptr } - } -} +// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic +// argument. +kernel::impl_device_context_deref!(unsafe { Device }); impl From<&Device<device::Core>> for ARef<Device> { fn from(dev: &Device<device::Core>) -> Self { |