1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Generic implementation of device IDs. 4 //! 5 //! Each bus / subsystem that matches device and driver through a bus / subsystem specific ID is 6 //! expected to implement [`RawDeviceId`]. 7 8 use core::{ 9 marker::PhantomData, 10 mem::MaybeUninit, // 11 }; 12 13 /// Marker trait to indicate a Rust device ID type represents a corresponding C device ID type. 14 /// 15 /// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to 16 /// guarantee (at compile-time) zero-termination of device id tables provided by drivers. 17 /// 18 /// # Safety 19 /// 20 /// Implementers must ensure that `Self` is layout-compatible with [`RawDeviceId::RawType`]; 21 /// i.e. it's safe to transmute to `RawType`. 22 /// 23 /// This requirement is needed so `IdArray::new` can convert `Self` to `RawType` when building 24 /// the ID table. 25 /// 26 /// Ideally, this should be achieved using a const function that does conversion instead of 27 /// transmute; however, const trait functions relies on `const_trait_impl` unstable feature, 28 /// which is broken/gone in Rust 1.73. 29 pub unsafe trait RawDeviceId { 30 /// The raw type that holds the device id. 31 /// 32 /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array. 33 type RawType: Copy; 34 } 35 36 /// Extension trait for [`RawDeviceId`] for devices that embed an index or context value. 37 /// 38 /// This is typically used when the device ID struct includes a field like `driver_data` 39 /// that is used to store a pointer-sized value (e.g., an index or context pointer). 40 /// 41 /// # Safety 42 /// 43 /// Implementers must ensure that `DRIVER_DATA_OFFSET` is the correct offset (in bytes) to 44 /// the context/data field (e.g., the `driver_data` field) within the raw device ID structure. 45 /// This field must be correctly sized to hold a `usize`. 46 /// 47 /// Ideally, the data should be added during `Self` to `RawType` conversion, 48 /// but there's currently no way to do it when using traits in const. 49 pub unsafe trait RawDeviceIdIndex: RawDeviceId { 50 /// The offset (in bytes) to the context/data field in the raw device ID. 51 const DRIVER_DATA_OFFSET: usize; 52 53 /// Obtain the data pointer stored inside the device ID. 54 /// 55 /// # Safety 56 /// 57 /// `&Self` must be stored inside a `IdArray<Self, U>`. 58 unsafe fn info_unchecked<U>(&self) -> &'static U { 59 // SAFETY: By safety requirement of the trait, this is `self.driver_data as *const U` and by 60 // the safety requirement of the function, this is stored in `IdArray<Self, U>` so is 61 // convertible to `&'static U`. 62 unsafe { 63 core::ptr::from_ref(self) 64 .byte_add(Self::DRIVER_DATA_OFFSET) 65 .cast::<&U>() 66 .read() 67 } 68 } 69 70 /// Obtain the data pointer stored inside the device ID. 71 /// 72 /// # Safety 73 /// 74 /// `&Self` must be stored inside a `IdArray<Self, U>`, or has NULL (or 0) as driver data. 75 unsafe fn info_unchecked_opt<U>(&self) -> Option<&'static U> { 76 // SAFETY: By safety requirement of the trait, this is `self.driver_data as *const U` and by 77 // the safety requirement of the function, if this is stored in `IdArray<Self, U>`, this is 78 // convertible to `Option<&'static U>`. Otherwise it is NULL which is `None` as 79 // `Option<&U>`. 80 unsafe { 81 core::ptr::from_ref(self) 82 .byte_add(Self::DRIVER_DATA_OFFSET) 83 .cast::<Option<&U>>() 84 .read() 85 } 86 } 87 } 88 89 /// A zero-terminated device id array, followed by context data. 90 #[repr(C)] 91 pub struct IdArray<T: RawDeviceId, U: 'static, const N: usize> { 92 // This is `MaybeUninit<T::RawType>` so any bytes inside it can carry provenance in CTFE. 93 // If this were `T::RawType`, integer fields would not be able to contain pointers. 94 ids: [MaybeUninit<T::RawType>; N], 95 sentinel: MaybeUninit<T::RawType>, 96 phantom: PhantomData<&'static U>, 97 } 98 99 // SAFETY: device ID is plain data plus a `&'static U` and can thus be sent between threads safely 100 // if `&U` can. 101 unsafe impl<T: RawDeviceId, U: Sync + 'static, const N: usize> Send for IdArray<T, U, N> {} 102 103 // SAFETY: device ID is plain data plus a `&'static U` and can thus be shared between threads safely 104 // if `&U` can. 105 unsafe impl<T: RawDeviceId, U: Sync + 'static, const N: usize> Sync for IdArray<T, U, N> {} 106 107 impl<T: RawDeviceId + RawDeviceIdIndex, U: 'static, const N: usize> IdArray<T, U, N> { 108 /// Creates a new instance of the array. 109 /// 110 /// The contents are derived from the given identifiers and context information. 111 pub const fn new(ids: [(T, &'static U); N]) -> Self { 112 let mut raw_ids = [const { MaybeUninit::<T::RawType>::uninit() }; N]; 113 114 let mut i = 0usize; 115 while i < N { 116 // SAFETY: by the safety requirement of `RawDeviceId`, we're guaranteed that `T` is 117 // layout-wise compatible with `RawType`. 118 raw_ids[i] = unsafe { core::mem::transmute_copy(&ids[i].0) }; 119 // SAFETY: by the safety requirement of `RawDeviceIdIndex`, this would be effectively 120 // `raw_ids[i].driver_data = ids[i].1;`. 121 unsafe { 122 raw_ids[i] 123 .as_mut_ptr() 124 .byte_add(T::DRIVER_DATA_OFFSET) 125 .cast::<&U>() 126 .write(ids[i].1); 127 } 128 129 i += 1; 130 } 131 132 core::mem::forget(ids); 133 134 Self { 135 ids: raw_ids, 136 sentinel: MaybeUninit::zeroed(), 137 phantom: PhantomData, 138 } 139 } 140 } 141 142 impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> { 143 /// Creates a new instance of the array without writing index values. 144 /// 145 /// The contents are derived from the given identifiers and context information. 146 /// If the device implements [`RawDeviceIdIndex`], consider using [`IdArray::new`] instead. 147 pub const fn new_without_index(ids: [T; N]) -> Self { 148 // SAFETY: `T` is layout-wise compatible with `T::RawType`, so is the array of them. 149 let raw_ids: [MaybeUninit<T::RawType>; N] = unsafe { core::mem::transmute_copy(&ids) }; 150 core::mem::forget(ids); 151 152 Self { 153 ids: raw_ids, 154 sentinel: MaybeUninit::zeroed(), 155 phantom: PhantomData, 156 } 157 } 158 } 159 160 /// A device id table. 161 /// 162 /// This trait is only implemented by `IdArray`. 163 /// 164 /// The purpose of this trait is to allow `&'static dyn IdArray<T, U>` to be in context when `N` in 165 /// `IdArray` doesn't matter. 166 pub trait IdTable<T: RawDeviceId, U> { 167 /// Obtain the pointer to the ID table. 168 fn as_ptr(&self) -> *const T::RawType; 169 } 170 171 impl<T: RawDeviceId, U, const N: usize> IdTable<T, U> for IdArray<T, U, N> { 172 fn as_ptr(&self) -> *const T::RawType { 173 // This cannot be `self.ids.as_ptr()`, as the return pointer must have correct provenance 174 // to access the sentinel. 175 core::ptr::from_ref(self).cast() 176 } 177 } 178 179 /// Create device table alias for modpost. 180 #[macro_export] 181 macro_rules! module_device_table { 182 ( 183 $table_type: literal, $device_id_ty: ty, 184 $table_name: ident, $id_info_type: ty, 185 [$(($id: expr, $info:expr $(,)?)),* $(,)?] 186 ) => { 187 #[export_name = 188 concat!("__mod_device_table__", ::core::line!(), 189 "__kmod_", module_path!(), 190 "__", $table_type, 191 "__", stringify!($table_name)) 192 ] 193 static $table_name: $crate::device_id::IdArray< 194 $device_id_ty, 195 $id_info_type, 196 { <[$device_id_ty]>::len(&[$($id,)*]) }, 197 > = $crate::device_id::IdArray::new([$(($id, &$info),)*]); 198 }; 199 200 // Case for no ID info. 201 ( 202 $table_type: literal, $device_id_ty: ty, 203 $table_name: ident, @none, 204 [$($id: expr),* $(,)?] 205 ) => { 206 #[export_name = 207 concat!("__mod_device_table__", ::core::line!(), 208 "__kmod_", module_path!(), 209 "__", $table_type, 210 "__", stringify!($table_name)) 211 ] 212 static $table_name: $crate::device_id::IdArray< 213 $device_id_ty, 214 (), 215 { <[$device_id_ty]>::len(&[$($id,)*]) }, 216 > = $crate::device_id::IdArray::new_without_index([$($id),*]); 217 }; 218 } 219