@@ -218,6 +218,93 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
218218 self . dma_handle
219219 }
220220
221+ /// Common helper to validate a range applied from the allocated region in the CPU's virtual
222+ /// address space.
223+ fn validate_range ( & self , offset : usize , count : usize ) -> Result {
224+ if offset. checked_add ( count) . ok_or ( EOVERFLOW ) ? > self . count {
225+ return Err ( EINVAL ) ;
226+ }
227+ Ok ( ( ) )
228+ }
229+
230+ /// Returns the data from the region starting from `offset` as a slice.
231+ /// `offset` and `count` are in units of `T`, not the number of bytes.
232+ ///
233+ /// For ringbuffer type of r/w access or use-cases where the pointer to the live data is needed,
234+ /// [`CoherentAllocation::start_ptr`] or [`CoherentAllocation::start_ptr_mut`] could be used
235+ /// instead.
236+ ///
237+ /// # Safety
238+ ///
239+ /// * Callers must ensure that the device does not read/write to/from memory while the returned
240+ /// slice is live.
241+ /// * Callers must ensure that this call does not race with a write to the same region while
242+ /// the returned slice is live.
243+ pub unsafe fn as_slice ( & self , offset : usize , count : usize ) -> Result < & [ T ] > {
244+ self . validate_range ( offset, count) ?;
245+ // SAFETY:
246+ // - The pointer is valid due to type invariant on `CoherentAllocation`,
247+ // we've just checked that the range and index is within bounds. The immutability of the
248+ // data is also guaranteed by the safety requirements of the function.
249+ // - `offset + count` can't overflow since it is smaller than `self.count` and we've checked
250+ // that `self.count` won't overflow early in the constructor.
251+ Ok ( unsafe { core:: slice:: from_raw_parts ( self . cpu_addr . add ( offset) , count) } )
252+ }
253+
254+ /// Performs the same functionality as [`CoherentAllocation::as_slice`], except that a mutable
255+ /// slice is returned.
256+ ///
257+ /// # Safety
258+ ///
259+ /// * Callers must ensure that the device does not read/write to/from memory while the returned
260+ /// slice is live.
261+ /// * Callers must ensure that this call does not race with a read or write to the same region
262+ /// while the returned slice is live.
263+ pub unsafe fn as_slice_mut ( & self , offset : usize , count : usize ) -> Result < & mut [ T ] > {
264+ self . validate_range ( offset, count) ?;
265+ // SAFETY:
266+ // - The pointer is valid due to type invariant on `CoherentAllocation`,
267+ // we've just checked that the range and index is within bounds. The immutability of the
268+ // data is also guaranteed by the safety requirements of the function.
269+ // - `offset + count` can't overflow since it is smaller than `self.count` and we've checked
270+ // that `self.count` won't overflow early in the constructor.
271+ Ok ( unsafe { core:: slice:: from_raw_parts_mut ( self . cpu_addr . add ( offset) , count) } )
272+ }
273+
274+ /// Writes data to the region starting from `offset`. `offset` is in units of `T`, not the
275+ /// number of bytes.
276+ ///
277+ /// # Safety
278+ ///
279+ /// * Callers must ensure that the device does not read/write to/from memory while the returned
280+ /// slice is live.
281+ /// * Callers must ensure that this call does not race with a read or write to the same region
282+ /// that overlaps with this write.
283+ ///
284+ /// # Examples
285+ ///
286+ /// ```
287+ /// # fn test(alloc: &mut kernel::dma::CoherentAllocation<u8>) -> Result {
288+ /// let somedata: [u8; 4] = [0xf; 4];
289+ /// let buf: &[u8] = &somedata;
290+ /// // SAFETY: There is no concurrent HW operation on the device and no other R/W access to the
291+ /// // region.
292+ /// unsafe { alloc.write(buf, 0)?; }
293+ /// # Ok::<(), Error>(()) }
294+ /// ```
295+ pub unsafe fn write ( & self , src : & [ T ] , offset : usize ) -> Result {
296+ self . validate_range ( offset, src. len ( ) ) ?;
297+ // SAFETY:
298+ // - The pointer is valid due to type invariant on `CoherentAllocation`
299+ // and we've just checked that the range and index is within bounds.
300+ // - `offset + count` can't overflow since it is smaller than `self.count` and we've checked
301+ // that `self.count` won't overflow early in the constructor.
302+ unsafe {
303+ core:: ptr:: copy_nonoverlapping ( src. as_ptr ( ) , self . cpu_addr . add ( offset) , src. len ( ) )
304+ } ;
305+ Ok ( ( ) )
306+ }
307+
221308 /// Returns a pointer to an element from the region with bounds checking. `offset` is in
222309 /// units of `T`, not the number of bytes.
223310 ///
0 commit comments