33//! Generic memory-mapped IO.
44
55use core:: ops:: Deref ;
6+ use core:: ptr:: NonNull ;
67
78use crate :: device:: Device ;
89use crate :: devres:: Devres ;
@@ -12,6 +13,7 @@ use crate::io::resource::Resource;
1213use crate :: io:: Io ;
1314use crate :: io:: IoRaw ;
1415use crate :: prelude:: * ;
16+ use crate :: types:: declare_flags_type;
1517
1618/// An exclusive memory-mapped IO region.
1719///
@@ -128,3 +130,104 @@ impl<const SIZE: usize> Deref for IoMem<SIZE> {
128130 unsafe { Io :: from_raw ( & self . io ) }
129131 }
130132}
133+
134+ declare_flags_type ! {
135+ /// Flags to be used when remapping memory.
136+ ///
137+ /// They can be combined with the operators `|`, `&`, and `!`.
138+ pub struct MemFlags ( crate :: ffi:: c_ulong) = 0 ;
139+ }
140+
141+ impl MemFlags {
142+ /// Matches the default mapping for System RAM on the architecture.
143+ ///
144+ /// This is usually a read-allocate write-back cache. Moreover, if this flag is specified and
145+ /// the requested remap region is RAM, memremap() will bypass establishing a new mapping and
146+ /// instead return a pointer into the direct map.
147+ pub const WB : MemFlags = MemFlags ( bindings:: MEMREMAP_WB as _ ) ;
148+
149+ /// Establish a mapping whereby writes either bypass the cache or are written through to memory
150+ /// and never exist in a cache-dirty state with respect to program visibility.
151+ ///
152+ /// Attempts to map System RAM with this mapping type will fail.
153+ pub const WT : MemFlags = MemFlags ( bindings:: MEMREMAP_WT as _ ) ;
154+ /// Establish a writecombine mapping, whereby writes may be coalesced together (e.g. in the
155+ /// CPU's write buffers), but is otherwise uncached.
156+ ///
157+ /// Attempts to map System RAM with this mapping type will fail.
158+ pub const WC : MemFlags = MemFlags ( bindings:: MEMREMAP_WC as _ ) ;
159+
160+ // Note: Skipping MEMREMAP_ENC/DEC since they are under-documented and have zero
161+ // users outside of arch/x86.
162+ }
163+
164+ /// Represents a non-MMIO memory block. This is like [`IoMem`], but for cases where it is known
165+ /// that the resource being mapped does not have I/O side effects.
166+ // Invariants:
167+ // `ptr` is a non-null and valid address of at least `usize` bytes and returned by a `memremap`
168+ // call.
169+ // ```
170+ pub struct Mem {
171+ ptr : NonNull < crate :: ffi:: c_void > ,
172+ size : usize ,
173+ }
174+
175+ impl Mem {
176+ /// Tries to create a new instance of a memory block from a Resource.
177+ ///
178+ /// The resource described by `res` is mapped into the CPU's address space so that it can be
179+ /// accessed directly. It is also consumed by this function so that it can't be mapped again
180+ /// to a different address.
181+ ///
182+ /// If multiple caching flags are specified, the different mapping types will be attempted in
183+ /// the order [`MemFlags::WB`], [`MemFlags::WT`], [`MemFlags::WC`].
184+ ///
185+ /// # Flags
186+ ///
187+ /// * [`MemFlags::WB`]: Matches the default mapping for System RAM on the architecture.
188+ /// This is usually a read-allocate write-back cache. Moreover, if this flag is specified and
189+ /// the requested remap region is RAM, memremap() will bypass establishing a new mapping and
190+ /// instead return a pointer into the direct map.
191+ ///
192+ /// * [`MemFlags::WT`]: Establish a mapping whereby writes either bypass the cache or are written
193+ /// through to memory and never exist in a cache-dirty state with respect to program visibility.
194+ /// Attempts to map System RAM with this mapping type will fail.
195+ /// * [`MemFlags::WC`]: Establish a writecombine mapping, whereby writes may be coalesced together
196+ /// (e.g. in the CPU's write buffers), but is otherwise uncached. Attempts to map System RAM with
197+ /// this mapping type will fail.
198+ ///
199+ /// # Safety
200+ ///
201+ /// Callers must ensure that either (a) the resulting interface cannot be used to initiate DMA
202+ /// operations, or (b) that DMA operations initiated via the returned interface use DMA handles
203+ /// allocated through the `dma` module.
204+ pub unsafe fn try_new ( res : Resource , flags : MemFlags ) -> Result < Self > {
205+ let size: usize = res. size ( ) . try_into ( ) ?;
206+
207+ let addr = unsafe { bindings:: memremap ( res. start ( ) , size, flags. as_raw ( ) ) } ;
208+ let ptr = NonNull :: new ( addr) . ok_or ( ENOMEM ) ?;
209+ // INVARIANT: `ptr` is non-null and was returned by `memremap`, so it is valid.
210+ Ok ( Self { ptr, size } )
211+ }
212+
213+ /// Returns the base address of the memory mapping as a raw pointer.
214+ ///
215+ /// It is up to the caller to use this pointer safely, depending on the requirements of the
216+ /// hardware backing this memory block.
217+ pub fn ptr ( & self ) -> * mut u8 {
218+ self . ptr . cast ( ) . as_ptr ( )
219+ }
220+
221+ /// Returns the size of this mapped memory block.
222+ pub fn size ( & self ) -> usize {
223+ self . size
224+ }
225+ }
226+
227+ impl Drop for Mem {
228+ fn drop ( & mut self ) {
229+ // SAFETY: By the type invariant, `self.ptr` is a value returned by a previous successful
230+ // call to `memremap`.
231+ unsafe { bindings:: memunmap ( self . ptr . as_ptr ( ) ) } ;
232+ }
233+ }
0 commit comments