@@ -89,23 +89,23 @@ pub mod attrs {
8989 /// Forces contiguous allocation of the buffer in physical memory.
9090 pub const DMA_ATTR_FORCE_CONTIGUOUS : Attrs = Attrs ( bindings:: DMA_ATTR_FORCE_CONTIGUOUS ) ;
9191
92- /// This is a hint to the DMA-mapping subsystem that it's probably not worth the time to try
92+ /// Hints DMA-mapping subsystem that it's probably not worth the time to try
9393 /// to allocate memory to in a way that gives better TLB efficiency.
9494 pub const DMA_ATTR_ALLOC_SINGLE_PAGES : Attrs = Attrs ( bindings:: DMA_ATTR_ALLOC_SINGLE_PAGES ) ;
9595
9696 /// This tells the DMA-mapping subsystem to suppress allocation failure reports (similarly to
9797 /// `__GFP_NOWARN`).
9898 pub const DMA_ATTR_NO_WARN : Attrs = Attrs ( bindings:: DMA_ATTR_NO_WARN ) ;
9999
100- /// Used to indicate that the buffer is fully accessible at an elevated privilege level (and
100+ /// Indicates that the buffer is fully accessible at an elevated privilege level (and
101101 /// ideally inaccessible or at least read-only at lesser-privileged levels).
102102 pub const DMA_ATTR_PRIVILEGED : Attrs = Attrs ( bindings:: DMA_ATTR_PRIVILEGED ) ;
103103}
104104
105105/// An abstraction of the `dma_alloc_coherent` API.
106106///
107107/// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map
108- /// large consistent DMA regions.
108+ /// large coherent DMA regions.
109109///
110110/// A [`CoherentAllocation`] instance contains a pointer to the allocated region (in the
111111/// processor's virtual address space) and the device address which can be given to the device
@@ -114,9 +114,11 @@ pub mod attrs {
114114///
115115/// # Invariants
116116///
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.
117+ /// - For the lifetime of an instance of [`CoherentAllocation`], the `cpu_addr` is a valid pointer
118+ /// to an allocated region of coherent memory and `dma_handle` is the DMA address base of the
119+ /// region.
120+ /// - The size in bytes of the allocation is equal to `size_of::<T> * count`.
121+ /// - `size_of::<T> * count` fits into a `usize`.
120122// TODO
121123//
122124// DMA allocations potentially carry device resources (e.g.IOMMU mappings), hence for soundness
@@ -138,7 +140,7 @@ pub struct CoherentAllocation<T: AsBytes + FromBytes> {
138140}
139141
140142impl < T : AsBytes + FromBytes > CoherentAllocation < T > {
141- /// Allocates a region of `size_of::<T> * count` of consistent memory.
143+ /// Allocates a region of `size_of::<T> * count` of coherent memory.
142144 ///
143145 /// # Examples
144146 ///
@@ -179,9 +181,12 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
179181 if ret. is_null ( ) {
180182 return Err ( ENOMEM ) ;
181183 }
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.
184+ // INVARIANT:
185+ // - We just successfully allocated a coherent region which is accessible for
186+ // `count` elements, hence the cpu address is valid. We also hold a refcounted reference
187+ // to the device.
188+ // - The allocated `size` is equal to `size_of::<T> * count`.
189+ // - The allocated `size` fits into a `usize`.
185190 Ok ( Self {
186191 dev : dev. into ( ) ,
187192 dma_handle,
@@ -201,6 +206,21 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
201206 CoherentAllocation :: alloc_attrs ( dev, count, gfp_flags, Attrs ( 0 ) )
202207 }
203208
209+ /// Returns the number of elements `T` in this allocation.
210+ ///
211+ /// Note that this is not the size of the allocation in bytes, which is provided by
212+ /// [`Self::size`].
213+ pub fn count ( & self ) -> usize {
214+ self . count
215+ }
216+
217+ /// Returns the size in bytes of this allocation.
218+ pub fn size ( & self ) -> usize {
219+ // INVARIANT: The type invariant of `Self` guarantees that `size_of::<T> * count` fits into
220+ // a `usize`.
221+ self . count * core:: mem:: size_of :: < T > ( )
222+ }
223+
204224 /// Returns the base address to the allocated region in the CPU's virtual address space.
205225 pub fn start_ptr ( & self ) -> * const T {
206226 self . cpu_addr
@@ -212,12 +232,113 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
212232 self . cpu_addr
213233 }
214234
215- /// Returns a DMA handle which may given to the device as the DMA address base of
235+ /// Returns a DMA handle which may be given to the device as the DMA address base of
216236 /// the region.
217237 pub fn dma_handle ( & self ) -> bindings:: dma_addr_t {
218238 self . dma_handle
219239 }
220240
241+ /// Returns a DMA handle starting at `offset` (in units of `T`) which may be given to the
242+ /// device as the DMA address base of the region.
243+ ///
244+ /// Returns `EINVAL` if `offset` is not within the bounds of the allocation.
245+ pub fn dma_handle_with_offset ( & self , offset : usize ) -> Result < bindings:: dma_addr_t > {
246+ if offset >= self . count {
247+ Err ( EINVAL )
248+ } else {
249+ // INVARIANT: The type invariant of `Self` guarantees that `size_of::<T> * count` fits
250+ // into a `usize`, and `offset` is inferior to `count`.
251+ Ok ( self . dma_handle + ( offset * core:: mem:: size_of :: < T > ( ) ) as bindings:: dma_addr_t )
252+ }
253+ }
254+
255+ /// Common helper to validate a range applied from the allocated region in the CPU's virtual
256+ /// address space.
257+ fn validate_range ( & self , offset : usize , count : usize ) -> Result {
258+ if offset. checked_add ( count) . ok_or ( EOVERFLOW ) ? > self . count {
259+ return Err ( EINVAL ) ;
260+ }
261+ Ok ( ( ) )
262+ }
263+
264+ /// Returns the data from the region starting from `offset` as a slice.
265+ /// `offset` and `count` are in units of `T`, not the number of bytes.
266+ ///
267+ /// For ringbuffer type of r/w access or use-cases where the pointer to the live data is needed,
268+ /// [`CoherentAllocation::start_ptr`] or [`CoherentAllocation::start_ptr_mut`] could be used
269+ /// instead.
270+ ///
271+ /// # Safety
272+ ///
273+ /// * Callers must ensure that the device does not read/write to/from memory while the returned
274+ /// slice is live.
275+ /// * Callers must ensure that this call does not race with a write to the same region while
276+ /// the returned slice is live.
277+ pub unsafe fn as_slice ( & self , offset : usize , count : usize ) -> Result < & [ T ] > {
278+ self . validate_range ( offset, count) ?;
279+ // SAFETY:
280+ // - The pointer is valid due to type invariant on `CoherentAllocation`,
281+ // we've just checked that the range and index is within bounds. The immutability of the
282+ // data is also guaranteed by the safety requirements of the function.
283+ // - `offset + count` can't overflow since it is smaller than `self.count` and we've checked
284+ // that `self.count` won't overflow early in the constructor.
285+ Ok ( unsafe { core:: slice:: from_raw_parts ( self . cpu_addr . add ( offset) , count) } )
286+ }
287+
288+ /// Performs the same functionality as [`CoherentAllocation::as_slice`], except that a mutable
289+ /// slice is returned.
290+ ///
291+ /// # Safety
292+ ///
293+ /// * Callers must ensure that the device does not read/write to/from memory while the returned
294+ /// slice is live.
295+ /// * Callers must ensure that this call does not race with a read or write to the same region
296+ /// while the returned slice is live.
297+ pub unsafe fn as_slice_mut ( & self , offset : usize , count : usize ) -> Result < & mut [ T ] > {
298+ self . validate_range ( offset, count) ?;
299+ // SAFETY:
300+ // - The pointer is valid due to type invariant on `CoherentAllocation`,
301+ // we've just checked that the range and index is within bounds. The immutability of the
302+ // data is also guaranteed by the safety requirements of the function.
303+ // - `offset + count` can't overflow since it is smaller than `self.count` and we've checked
304+ // that `self.count` won't overflow early in the constructor.
305+ Ok ( unsafe { core:: slice:: from_raw_parts_mut ( self . cpu_addr . add ( offset) , count) } )
306+ }
307+
308+ /// Writes data to the region starting from `offset`. `offset` is in units of `T`, not the
309+ /// number of bytes.
310+ ///
311+ /// # Safety
312+ ///
313+ /// * Callers must ensure that the device does not read/write to/from memory while the returned
314+ /// slice is live.
315+ /// * Callers must ensure that this call does not race with a read or write to the same region
316+ /// that overlaps with this write.
317+ ///
318+ /// # Examples
319+ ///
320+ /// ```
321+ /// # fn test(alloc: &mut kernel::dma::CoherentAllocation<u8>) -> Result {
322+ /// let somedata: [u8; 4] = [0xf; 4];
323+ /// let buf: &[u8] = &somedata;
324+ /// // SAFETY: There is no concurrent HW operation on the device and no other R/W access to the
325+ /// // region.
326+ /// unsafe { alloc.write(buf, 0)?; }
327+ /// # Ok::<(), Error>(()) }
328+ /// ```
329+ pub unsafe fn write ( & self , src : & [ T ] , offset : usize ) -> Result {
330+ self . validate_range ( offset, src. len ( ) ) ?;
331+ // SAFETY:
332+ // - The pointer is valid due to type invariant on `CoherentAllocation`
333+ // and we've just checked that the range and index is within bounds.
334+ // - `offset + count` can't overflow since it is smaller than `self.count` and we've checked
335+ // that `self.count` won't overflow early in the constructor.
336+ unsafe {
337+ core:: ptr:: copy_nonoverlapping ( src. as_ptr ( ) , self . cpu_addr . add ( offset) , src. len ( ) )
338+ } ;
339+ Ok ( ( ) )
340+ }
341+
221342 /// Returns a pointer to an element from the region with bounds checking. `offset` is in
222343 /// units of `T`, not the number of bytes.
223344 ///
@@ -328,20 +449,24 @@ unsafe impl<T: AsBytes + FromBytes + Send> Send for CoherentAllocation<T> {}
328449#[ macro_export]
329450macro_rules! dma_read {
330451 ( $dma: expr, $idx: expr, $( $field: tt) * ) => { {
331- let item = $crate:: dma:: CoherentAllocation :: item_from_index( & $dma, $idx) ?;
332- // SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
333- // dereferenced. The compiler also further validates the expression on whether `field`
334- // is a member of `item` when expanded by the macro.
335- unsafe {
336- let ptr_field = :: core:: ptr:: addr_of!( ( * item) $( $field) * ) ;
337- $crate:: dma:: CoherentAllocation :: field_read( & $dma, ptr_field)
338- }
452+ ( || -> :: core:: result:: Result <_, $crate:: error:: Error > {
453+ let item = $crate:: dma:: CoherentAllocation :: item_from_index( & $dma, $idx) ?;
454+ // SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
455+ // dereferenced. The compiler also further validates the expression on whether `field`
456+ // is a member of `item` when expanded by the macro.
457+ unsafe {
458+ let ptr_field = :: core:: ptr:: addr_of!( ( * item) $( $field) * ) ;
459+ :: core:: result:: Result :: Ok (
460+ $crate:: dma:: CoherentAllocation :: field_read( & $dma, ptr_field)
461+ )
462+ }
463+ } ) ( )
339464 } } ;
340465 ( $dma: ident [ $idx: expr ] $( $field: tt) * ) => {
341- $crate:: dma_read!( $dma, $idx, $( $field) * ) ;
466+ $crate:: dma_read!( $dma, $idx, $( $field) * )
342467 } ;
343468 ( $( $dma: ident) .* [ $idx: expr ] $( $field: tt) * ) => {
344- $crate:: dma_read!( $( $dma) .* , $idx, $( $field) * ) ;
469+ $crate:: dma_read!( $( $dma) .* , $idx, $( $field) * )
345470 } ;
346471}
347472
@@ -368,24 +493,30 @@ macro_rules! dma_read {
368493#[ macro_export]
369494macro_rules! dma_write {
370495 ( $dma: ident [ $idx: expr ] $( $field: tt) * ) => { {
371- $crate:: dma_write!( $dma, $idx, $( $field) * ) ;
496+ $crate:: dma_write!( $dma, $idx, $( $field) * )
372497 } } ;
373498 ( $( $dma: ident) .* [ $idx: expr ] $( $field: tt) * ) => { {
374- $crate:: dma_write!( $( $dma) .* , $idx, $( $field) * ) ;
499+ $crate:: dma_write!( $( $dma) .* , $idx, $( $field) * )
375500 } } ;
376501 ( $dma: expr, $idx: expr, = $val: expr) => {
377- let item = $crate:: dma:: CoherentAllocation :: item_from_index( & $dma, $idx) ?;
378- // SAFETY: `item_from_index` ensures that `item` is always a valid item.
379- unsafe { $crate:: dma:: CoherentAllocation :: field_write( & $dma, item, $val) }
502+ ( || -> :: core:: result:: Result <_, $crate:: error:: Error > {
503+ let item = $crate:: dma:: CoherentAllocation :: item_from_index( & $dma, $idx) ?;
504+ // SAFETY: `item_from_index` ensures that `item` is always a valid item.
505+ unsafe { $crate:: dma:: CoherentAllocation :: field_write( & $dma, item, $val) }
506+ :: core:: result:: Result :: Ok ( ( ) )
507+ } ) ( )
380508 } ;
381509 ( $dma: expr, $idx: expr, $( . $field: ident) * = $val: expr) => {
382- let item = $crate:: dma:: CoherentAllocation :: item_from_index( & $dma, $idx) ?;
383- // SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
384- // dereferenced. The compiler also further validates the expression on whether `field`
385- // is a member of `item` when expanded by the macro.
386- unsafe {
387- let ptr_field = :: core:: ptr:: addr_of_mut!( ( * item) $( . $field) * ) ;
388- $crate:: dma:: CoherentAllocation :: field_write( & $dma, ptr_field, $val)
389- }
510+ ( || -> :: core:: result:: Result <_, $crate:: error:: Error > {
511+ let item = $crate:: dma:: CoherentAllocation :: item_from_index( & $dma, $idx) ?;
512+ // SAFETY: `item_from_index` ensures that `item` is always a valid pointer and can be
513+ // dereferenced. The compiler also further validates the expression on whether `field`
514+ // is a member of `item` when expanded by the macro.
515+ unsafe {
516+ let ptr_field = :: core:: ptr:: addr_of_mut!( ( * item) $( . $field) * ) ;
517+ $crate:: dma:: CoherentAllocation :: field_write( & $dma, ptr_field, $val)
518+ }
519+ :: core:: result:: Result :: Ok ( ( ) )
520+ } ) ( )
390521 } ;
391522}
0 commit comments