33//! Generic memory-mapped IO.
44
55use core:: ops:: Deref ;
6+ use core:: ptr:: NonNull ;
67
78use crate :: c_str;
89use crate :: device:: Bound ;
@@ -14,6 +15,7 @@ use crate::io::resource::Resource;
1415use crate :: io:: Io ;
1516use crate :: io:: IoRaw ;
1617use crate :: prelude:: * ;
18+ use crate :: types:: declare_flags_type;
1719
1820/// An IO request for a specific device and resource.
1921pub struct IoRequest < ' a > {
@@ -277,3 +279,104 @@ impl<const SIZE: usize> Deref for IoMem<SIZE> {
277279 unsafe { Io :: from_raw ( & self . io ) }
278280 }
279281}
282+
283+ declare_flags_type ! {
284+ /// Flags to be used when remapping memory.
285+ ///
286+ /// They can be combined with the operators `|`, `&`, and `!`.
287+ pub struct MemFlags ( crate :: ffi:: c_ulong) = 0 ;
288+ }
289+
290+ impl MemFlags {
291+ /// Matches the default mapping for System RAM on the architecture.
292+ ///
293+ /// This is usually a read-allocate write-back cache. Moreover, if this flag is specified and
294+ /// the requested remap region is RAM, memremap() will bypass establishing a new mapping and
295+ /// instead return a pointer into the direct map.
296+ pub const WB : MemFlags = MemFlags ( bindings:: MEMREMAP_WB as _ ) ;
297+
298+ /// Establish a mapping whereby writes either bypass the cache or are written through to memory
299+ /// and never exist in a cache-dirty state with respect to program visibility.
300+ ///
301+ /// Attempts to map System RAM with this mapping type will fail.
302+ pub const WT : MemFlags = MemFlags ( bindings:: MEMREMAP_WT as _ ) ;
303+ /// Establish a writecombine mapping, whereby writes may be coalesced together (e.g. in the
304+ /// CPU's write buffers), but is otherwise uncached.
305+ ///
306+ /// Attempts to map System RAM with this mapping type will fail.
307+ pub const WC : MemFlags = MemFlags ( bindings:: MEMREMAP_WC as _ ) ;
308+
309+ // Note: Skipping MEMREMAP_ENC/DEC since they are under-documented and have zero
310+ // users outside of arch/x86.
311+ }
312+
313+ /// Represents a non-MMIO memory block. This is like [`IoMem`], but for cases where it is known
314+ /// that the resource being mapped does not have I/O side effects.
315+ // Invariants:
316+ // `ptr` is a non-null and valid address of at least `usize` bytes and returned by a `memremap`
317+ // call.
318+ // ```
319+ pub struct Mem {
320+ ptr : NonNull < crate :: ffi:: c_void > ,
321+ size : usize ,
322+ }
323+
324+ impl Mem {
325+ /// Tries to create a new instance of a memory block from a Resource.
326+ ///
327+ /// The resource described by `res` is mapped into the CPU's address space so that it can be
328+ /// accessed directly. It is also consumed by this function so that it can't be mapped again
329+ /// to a different address.
330+ ///
331+ /// If multiple caching flags are specified, the different mapping types will be attempted in
332+ /// the order [`MemFlags::WB`], [`MemFlags::WT`], [`MemFlags::WC`].
333+ ///
334+ /// # Flags
335+ ///
336+ /// * [`MemFlags::WB`]: Matches the default mapping for System RAM on the architecture.
337+ /// This is usually a read-allocate write-back cache. Moreover, if this flag is specified and
338+ /// the requested remap region is RAM, memremap() will bypass establishing a new mapping and
339+ /// instead return a pointer into the direct map.
340+ ///
341+ /// * [`MemFlags::WT`]: Establish a mapping whereby writes either bypass the cache or are written
342+ /// through to memory and never exist in a cache-dirty state with respect to program visibility.
343+ /// Attempts to map System RAM with this mapping type will fail.
344+ /// * [`MemFlags::WC`]: Establish a writecombine mapping, whereby writes may be coalesced together
345+ /// (e.g. in the CPU's write buffers), but is otherwise uncached. Attempts to map System RAM with
346+ /// this mapping type will fail.
347+ ///
348+ /// # Safety
349+ ///
350+ /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
351+ /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
352+ /// allocated through the `dma` module.
353+ pub unsafe fn try_new ( res : Resource , flags : MemFlags ) -> Result < Self > {
354+ let size: usize = res. size ( ) . try_into ( ) ?;
355+
356+ let addr = unsafe { bindings:: memremap ( res. start ( ) , size, flags. as_raw ( ) ) } ;
357+ let ptr = NonNull :: new ( addr) . ok_or ( ENOMEM ) ?;
358+ // INVARIANT: `ptr` is non-null and was returned by `memremap`, so it is valid.
359+ Ok ( Self { ptr, size } )
360+ }
361+
362+ /// Returns the base address of the memory mapping as a raw pointer.
363+ ///
364+ /// It is up to the caller to use this pointer safely, depending on the requirements of the
365+ /// hardware backing this memory block.
366+ pub fn ptr ( & self ) -> * mut u8 {
367+ self . ptr . cast ( ) . as_ptr ( )
368+ }
369+
370+ /// Returns the size of this mapped memory block.
371+ pub fn size ( & self ) -> usize {
372+ self . size
373+ }
374+ }
375+
376+ impl Drop for Mem {
377+ fn drop ( & mut self ) {
378+ // SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful
379+ // call to `memremap`.
380+ unsafe { bindings:: memunmap ( self . ptr . as_ptr ( ) ) } ;
381+ }
382+ }
0 commit comments