|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | + |
| 3 | +//! Direct memory access (DMA). |
| 4 | +//! |
| 5 | +//! C header: [`include/linux/dma-mapping.h`](srctree/include/linux/dma-mapping.h) |
| 6 | +
|
| 7 | +use crate::{ |
| 8 | + bindings, build_assert, |
| 9 | + device::Device, |
| 10 | + error::code::*, |
| 11 | + error::Result, |
| 12 | + transmute::{AsBytes, FromBytes}, |
| 13 | + types::ARef, |
| 14 | +}; |
| 15 | + |
| 16 | +/// Possible attributes associated with a DMA mapping. |
| 17 | +/// |
| 18 | +/// They can be combined with the operators `|`, `&`, and `!`. |
| 19 | +/// |
| 20 | +/// Values can be used from the [`attrs`] module. |
| 21 | +/// |
| 22 | +/// # Examples |
| 23 | +/// |
| 24 | +/// ``` |
| 25 | +/// use kernel::device::Device; |
| 26 | +/// use kernel::dma::{attrs::*, CoherentAllocation}; |
| 27 | +/// |
| 28 | +/// # fn test(dev: &Device) -> Result { |
| 29 | +/// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN; |
| 30 | +/// let c: CoherentAllocation<u64> = |
| 31 | +/// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, attribs)?; |
| 32 | +/// # Ok::<(), Error>(()) } |
| 33 | +/// ``` |
| 34 | +#[derive(Clone, Copy, PartialEq)] |
| 35 | +#[repr(transparent)] |
| 36 | +pub struct Attrs(u32); |
| 37 | + |
| 38 | +impl Attrs { |
| 39 | + /// Get the raw representation of this attribute. |
| 40 | + pub(crate) fn as_raw(self) -> crate::ffi::c_ulong { |
| 41 | + self.0 as _ |
| 42 | + } |
| 43 | + |
| 44 | + /// Check whether `flags` is contained in `self`. |
| 45 | + pub fn contains(self, flags: Attrs) -> bool { |
| 46 | + (self & flags) == flags |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +impl core::ops::BitOr for Attrs { |
| 51 | + type Output = Self; |
| 52 | + fn bitor(self, rhs: Self) -> Self::Output { |
| 53 | + Self(self.0 | rhs.0) |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +impl core::ops::BitAnd for Attrs { |
| 58 | + type Output = Self; |
| 59 | + fn bitand(self, rhs: Self) -> Self::Output { |
| 60 | + Self(self.0 & rhs.0) |
| 61 | + } |
| 62 | +} |
| 63 | + |
| 64 | +impl core::ops::Not for Attrs { |
| 65 | + type Output = Self; |
| 66 | + fn not(self) -> Self::Output { |
| 67 | + Self(!self.0) |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +/// DMA mapping attributes. |
| 72 | +pub mod attrs { |
| 73 | + use super::Attrs; |
| 74 | + |
| 75 | + /// Specifies that reads and writes to the mapping may be weakly ordered, that is that reads |
| 76 | + /// and writes may pass each other. |
| 77 | + pub const DMA_ATTR_WEAK_ORDERING: Attrs = Attrs(bindings::DMA_ATTR_WEAK_ORDERING); |
| 78 | + |
| 79 | + /// Specifies that writes to the mapping may be buffered to improve performance. |
| 80 | + pub const DMA_ATTR_WRITE_COMBINE: Attrs = Attrs(bindings::DMA_ATTR_WRITE_COMBINE); |
| 81 | + |
| 82 | + /// Lets the platform to avoid creating a kernel virtual mapping for the allocated buffer. |
| 83 | + pub const DMA_ATTR_NO_KERNEL_MAPPING: Attrs = Attrs(bindings::DMA_ATTR_NO_KERNEL_MAPPING); |
| 84 | + |
| 85 | + /// Allows platform code to skip synchronization of the CPU cache for the given buffer assuming |
| 86 | + /// that it has been already transferred to 'device' domain. |
| 87 | + pub const DMA_ATTR_SKIP_CPU_SYNC: Attrs = Attrs(bindings::DMA_ATTR_SKIP_CPU_SYNC); |
| 88 | + |
| 89 | + /// Forces contiguous allocation of the buffer in physical memory. |
| 90 | + pub const DMA_ATTR_FORCE_CONTIGUOUS: Attrs = Attrs(bindings::DMA_ATTR_FORCE_CONTIGUOUS); |
| 91 | + |
| 92 | + /// This is a hint to the DMA-mapping subsystem that it's probably not worth the time to try |
| 93 | + /// to allocate memory to in a way that gives better TLB efficiency. |
| 94 | + pub const DMA_ATTR_ALLOC_SINGLE_PAGES: Attrs = Attrs(bindings::DMA_ATTR_ALLOC_SINGLE_PAGES); |
| 95 | + |
| 96 | + /// This tells the DMA-mapping subsystem to suppress allocation failure reports (similarly to |
| 97 | + /// __GFP_NOWARN). |
| 98 | + pub const DMA_ATTR_NO_WARN: Attrs = Attrs(bindings::DMA_ATTR_NO_WARN); |
| 99 | + |
| 100 | + /// Used to indicate that the buffer is fully accessible at an elevated privilege level (and |
| 101 | + /// ideally inaccessible or at least read-only at lesser-privileged levels). |
| 102 | + pub const DMA_ATTR_PRIVILEGED: Attrs = Attrs(bindings::DMA_ATTR_PRIVILEGED); |
| 103 | +} |
| 104 | + |
| 105 | +/// An abstraction of the `dma_alloc_coherent` API. |
| 106 | +/// |
| 107 | +/// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map |
| 108 | +/// large consistent DMA regions. |
| 109 | +/// |
| 110 | +/// A [`CoherentAllocation`] instance contains a pointer to the allocated region (in the |
| 111 | +/// processor's virtual address space) and the device address which can be given to the device |
| 112 | +/// as the DMA address base of the region. The region is released once [`CoherentAllocation`] |
| 113 | +/// is dropped. |
| 114 | +/// |
| 115 | +/// # Invariants |
| 116 | +/// |
| 117 | +/// For the lifetime of an instance of [`CoherentAllocation`], the `cpu_addr` is a valid pointer |
| 118 | +/// to an allocated region of consistent memory and `dma_handle` is the DMA address base of |
| 119 | +/// the region. |
| 120 | +// TODO |
| 121 | +// |
| 122 | +// DMA allocations potentially carry device resources (e.g.IOMMU mappings), hence for soundness |
| 123 | +// reasons DMA allocation would need to be embedded in a `Devres` container, in order to ensure |
| 124 | +// that device resources can never survive device unbind. |
| 125 | +// |
| 126 | +// However, it is neither desirable nor necessary to protect the allocated memory of the DMA |
| 127 | +// allocation from surviving device unbind; it would require RCU read side critical sections to |
| 128 | +// access the memory, which may require subsequent unnecessary copies. |
| 129 | +// |
| 130 | +// Hence, find a way to revoke the device resources of a `CoherentAllocation`, but not the |
| 131 | +// entire `CoherentAllocation` including the allocated memory itself. |
| 132 | +pub struct CoherentAllocation<T: AsBytes + FromBytes> { |
| 133 | + dev: ARef<Device>, |
| 134 | + dma_handle: bindings::dma_addr_t, |
| 135 | + count: usize, |
| 136 | + cpu_addr: *mut T, |
| 137 | + dma_attrs: Attrs, |
| 138 | +} |
| 139 | + |
| 140 | +impl<T: AsBytes + FromBytes> CoherentAllocation<T> { |
| 141 | + /// Allocates a region of `size_of::<T> * count` of consistent memory. |
| 142 | + /// |
| 143 | + /// # Examples |
| 144 | + /// |
| 145 | + /// ``` |
| 146 | + /// use kernel::device::Device; |
| 147 | + /// use kernel::dma::{attrs::*, CoherentAllocation}; |
| 148 | + /// |
| 149 | + /// # fn test(dev: &Device) -> Result { |
| 150 | + /// let c: CoherentAllocation<u64> = |
| 151 | + /// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?; |
| 152 | + /// # Ok::<(), Error>(()) } |
| 153 | + /// ``` |
| 154 | + pub fn alloc_attrs( |
| 155 | + dev: &Device, |
| 156 | + count: usize, |
| 157 | + gfp_flags: kernel::alloc::Flags, |
| 158 | + dma_attrs: Attrs, |
| 159 | + ) -> Result<CoherentAllocation<T>> { |
| 160 | + build_assert!( |
| 161 | + core::mem::size_of::<T>() > 0, |
| 162 | + "It doesn't make sense for the allocated type to be a ZST" |
| 163 | + ); |
| 164 | + |
| 165 | + let size = count |
| 166 | + .checked_mul(core::mem::size_of::<T>()) |
| 167 | + .ok_or(EOVERFLOW)?; |
| 168 | + let mut dma_handle = 0; |
| 169 | + // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`. |
| 170 | + let ret = unsafe { |
| 171 | + bindings::dma_alloc_attrs( |
| 172 | + dev.as_raw(), |
| 173 | + size, |
| 174 | + &mut dma_handle, |
| 175 | + gfp_flags.as_raw(), |
| 176 | + dma_attrs.as_raw(), |
| 177 | + ) |
| 178 | + }; |
| 179 | + if ret.is_null() { |
| 180 | + return Err(ENOMEM); |
| 181 | + } |
| 182 | + // INVARIANT: We just successfully allocated a coherent region which is accessible for |
| 183 | + // `count` elements, hence the cpu address is valid. We also hold a refcounted reference |
| 184 | + // to the device. |
| 185 | + Ok(Self { |
| 186 | + dev: dev.into(), |
| 187 | + dma_handle, |
| 188 | + count, |
| 189 | + cpu_addr: ret as *mut T, |
| 190 | + dma_attrs, |
| 191 | + }) |
| 192 | + } |
| 193 | + |
| 194 | + /// Performs the same functionality as [`CoherentAllocation::alloc_attrs`], except the |
| 195 | + /// `dma_attrs` is 0 by default. |
| 196 | + pub fn alloc_coherent( |
| 197 | + dev: &Device, |
| 198 | + count: usize, |
| 199 | + gfp_flags: kernel::alloc::Flags, |
| 200 | + ) -> Result<CoherentAllocation<T>> { |
| 201 | + CoherentAllocation::alloc_attrs(dev, count, gfp_flags, Attrs(0)) |
| 202 | + } |
| 203 | + |
| 204 | + /// Returns the base address to the allocated region in the CPU's virtual address space. |
| 205 | + pub fn start_ptr(&self) -> *const T { |
| 206 | + self.cpu_addr |
| 207 | + } |
| 208 | + |
| 209 | + /// Returns the base address to the allocated region in the CPU's virtual address space as |
| 210 | + /// a mutable pointer. |
| 211 | + pub fn start_ptr_mut(&mut self) -> *mut T { |
| 212 | + self.cpu_addr |
| 213 | + } |
| 214 | + |
| 215 | + /// Returns a DMA handle which may given to the device as the DMA address base of |
| 216 | + /// the region. |
| 217 | + pub fn dma_handle(&self) -> bindings::dma_addr_t { |
| 218 | + self.dma_handle |
| 219 | + } |
| 220 | + |
| 221 | + /// Returns a pointer to an element from the region with bounds checking. `offset` is in |
| 222 | + /// units of `T`, not the number of bytes. |
| 223 | + /// |
| 224 | + /// Public but hidden since it should only be used from [`dma_read`] and [`dma_write`] macros. |
| 225 | + #[doc(hidden)] |
| 226 | + pub fn item_from_index(&self, offset: usize) -> Result<*mut T> { |
| 227 | + if offset >= self.count { |
| 228 | + return Err(EINVAL); |
| 229 | + } |
| 230 | + // SAFETY: |
| 231 | + // - The pointer is valid due to type invariant on `CoherentAllocation` |
| 232 | + // and we've just checked that the range and index is within bounds. |
| 233 | + // - `offset` can't overflow since it is smaller than `self.count` and we've checked |
| 234 | + // that `self.count` won't overflow early in the constructor. |
| 235 | + Ok(unsafe { self.cpu_addr.add(offset) }) |
| 236 | + } |
| 237 | + |
| 238 | + /// Reads the value of `field` and ensures that its type is [`FromBytes`]. |
| 239 | + /// |
| 240 | + /// # Safety |
| 241 | + /// |
| 242 | + /// This must be called from the [`dma_read`] macro which ensures that the `field` pointer is |
| 243 | + /// validated beforehand. |
| 244 | + /// |
| 245 | + /// Public but hidden since it should only be used from [`dma_read`] macro. |
| 246 | + #[doc(hidden)] |
| 247 | + pub unsafe fn field_read<F: FromBytes>(&self, field: *const F) -> F { |
| 248 | + // SAFETY: |
| 249 | + // - By the safety requirements field is valid. |
| 250 | + // - Using read_volatile() here is not sound as per the usual rules, the usage here is |
| 251 | + // a special exception with the following notes in place. When dealing with a potential |
| 252 | + // race from a hardware or code outside kernel (e.g. user-space program), we need that |
| 253 | + // read on a valid memory is not UB. Currently read_volatile() is used for this, and the |
| 254 | + // rationale behind is that it should generate the same code as READ_ONCE() which the |
| 255 | + // kernel already relies on to avoid UB on data races. Note that the usage of |
| 256 | + // read_volatile() is limited to this particular case, it cannot be used to prevent |
| 257 | + // the UB caused by racing between two kernel functions nor do they provide atomicity. |
| 258 | + unsafe { field.read_volatile() } |
| 259 | + } |
| 260 | + |
| 261 | + /// Writes a value to `field` and ensures that its type is [`AsBytes`]. |
| 262 | + /// |
| 263 | + /// # Safety |
| 264 | + /// |
| 265 | + /// This must be called from the [`dma_write`] macro which ensures that the `field` pointer is |
| 266 | + /// validated beforehand. |
| 267 | + /// |
| 268 | + /// Public but hidden since it should only be used from [`dma_write`] macro. |
| 269 | + #[doc(hidden)] |
| 270 | + pub unsafe fn field_write<F: AsBytes>(&self, field: *mut F, val: F) { |
| 271 | + // SAFETY: |
| 272 | + // - By the safety requirements field is valid. |
| 273 | + // - Using write_volatile() here is not sound as per the usual rules, the usage here is |
| 274 | + // a special exception with the following notes in place. When dealing with a potential |
| 275 | + // race from a hardware or code outside kernel (e.g. user-space program), we need that |
| 276 | + // write on a valid memory is not UB. Currently write_volatile() is used for this, and the |
| 277 | + // rationale behind is that it should generate the same code as WRITE_ONCE() which the |
| 278 | + // kernel already relies on to avoid UB on data races. Note that the usage of |
| 279 | + // write_volatile() is limited to this particular case, it cannot be used to prevent |
| 280 | + // the UB caused by racing between two kernel functions nor do they provide atomicity. |
| 281 | + unsafe { field.write_volatile(val) } |
| 282 | + } |
| 283 | +} |
| 284 | + |
| 285 | +/// Note that the device configured to do DMA must be halted before this object is dropped. |
| 286 | +impl<T: AsBytes + FromBytes> Drop for CoherentAllocation<T> { |
| 287 | + fn drop(&mut self) { |
| 288 | + let size = self.count * core::mem::size_of::<T>(); |
| 289 | + // SAFETY: Device pointer is guaranteed as valid by the type invariant on `Device`. |
| 290 | + // The cpu address, and the dma handle are valid due to the type invariants on |
| 291 | + // `CoherentAllocation`. |
| 292 | + unsafe { |
| 293 | + bindings::dma_free_attrs( |
| 294 | + self.dev.as_raw(), |
| 295 | + size, |
| 296 | + self.cpu_addr as _, |
| 297 | + self.dma_handle, |
| 298 | + self.dma_attrs.as_raw(), |
| 299 | + ) |
| 300 | + } |
| 301 | + } |
| 302 | +} |
| 303 | + |
| 304 | +/// Reads a field of an item from an allocated region of structs. |
| 305 | +/// |
| 306 | +/// # Examples |
| 307 | +/// |
| 308 | +/// ``` |
| 309 | +/// use kernel::device::Device; |
| 310 | +/// use kernel::dma::{attrs::*, CoherentAllocation}; |
| 311 | +/// |
| 312 | +/// struct MyStruct { field: u32, } |
| 313 | +/// |
| 314 | +/// // SAFETY: All bit patterns are acceptable values for `MyStruct`. |
| 315 | +/// unsafe impl kernel::transmute::FromBytes for MyStruct{}; |
| 316 | +/// // SAFETY: Instances of `MyStruct` have no uninitialized portions. |
| 317 | +/// unsafe impl kernel::transmute::AsBytes for MyStruct{}; |
| 318 | +/// |
| 319 | +/// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result { |
| 320 | +/// let whole = kernel::dma_read!(alloc[2]); |
| 321 | +/// let field = kernel::dma_read!(alloc[1].field); |
| 322 | +/// # Ok::<(), Error>(()) } |
| 323 | +/// ``` |
| 324 | +#[macro_export] |
| 325 | +macro_rules! dma_read { |
| 326 | + ($dma:expr, $idx: expr, $($field:tt)*) => {{ |
| 327 | + let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?; |
| 328 | + // SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be |
| 329 | + // dereferenced. The compiler also further validates the expression on whether `field` |
| 330 | + // is a member of `item` when expanded by the macro. |
| 331 | + unsafe { |
| 332 | + let ptr_field = ::core::ptr::addr_of!((*item) $($field)*); |
| 333 | + $crate::dma::CoherentAllocation::field_read(&$dma, ptr_field) |
| 334 | + } |
| 335 | + }}; |
| 336 | + ($dma:ident [ $idx:expr ] $($field:tt)* ) => { |
| 337 | + $crate::dma_read!($dma, $idx, $($field)*); |
| 338 | + }; |
| 339 | + ($($dma:ident).* [ $idx:expr ] $($field:tt)* ) => { |
| 340 | + $crate::dma_read!($($dma).*, $idx, $($field)*); |
| 341 | + }; |
| 342 | +} |
| 343 | + |
| 344 | +/// Writes to a field of an item from an allocated region of structs. |
| 345 | +/// |
| 346 | +/// # Examples |
| 347 | +/// |
| 348 | +/// ``` |
| 349 | +/// use kernel::device::Device; |
| 350 | +/// use kernel::dma::{attrs::*, CoherentAllocation}; |
| 351 | +/// |
| 352 | +/// struct MyStruct { member: u32, } |
| 353 | +/// |
| 354 | +/// // SAFETY: All bit patterns are acceptable values for `MyStruct`. |
| 355 | +/// unsafe impl kernel::transmute::FromBytes for MyStruct{}; |
| 356 | +/// // SAFETY: Instances of `MyStruct` have no uninitialized portions. |
| 357 | +/// unsafe impl kernel::transmute::AsBytes for MyStruct{}; |
| 358 | +/// |
| 359 | +/// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result { |
| 360 | +/// kernel::dma_write!(alloc[2].member = 0xf); |
| 361 | +/// kernel::dma_write!(alloc[1] = MyStruct { member: 0xf }); |
| 362 | +/// # Ok::<(), Error>(()) } |
| 363 | +/// ``` |
| 364 | +#[macro_export] |
| 365 | +macro_rules! dma_write { |
| 366 | + ($dma:ident [ $idx:expr ] $($field:tt)*) => {{ |
| 367 | + $crate::dma_write!($dma, $idx, $($field)*); |
| 368 | + }}; |
| 369 | + ($($dma:ident).* [ $idx:expr ] $($field:tt)* ) => {{ |
| 370 | + $crate::dma_write!($($dma).*, $idx, $($field)*); |
| 371 | + }}; |
| 372 | + ($dma:expr, $idx: expr, = $val:expr) => { |
| 373 | + let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?; |
| 374 | + // SAFETY: `item_from_index` ensures that `item` is always a valid item. |
| 375 | + unsafe { $crate::dma::CoherentAllocation::field_write(&$dma, item, $val) } |
| 376 | + }; |
| 377 | + ($dma:expr, $idx: expr, $(.$field:ident)* = $val:expr) => { |
| 378 | + let item = $crate::dma::CoherentAllocation::item_from_index(&$dma, $idx)?; |
| 379 | + // SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be |
| 380 | + // dereferenced. The compiler also further validates the expression on whether `field` |
| 381 | + // is a member of `item` when expanded by the macro. |
| 382 | + unsafe { |
| 383 | + let ptr_field = ::core::ptr::addr_of_mut!((*item) $(.$field)*); |
| 384 | + $crate::dma::CoherentAllocation::field_write(&$dma, ptr_field, $val) |
| 385 | + } |
| 386 | + }; |
| 387 | +} |
0 commit comments