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