xref: /aosp_15_r20/external/virtio-media/device/src/mmap.rs (revision 1b4853f54772485c5dd4001ae33a7a958bcc97a1)
1*1b4853f5SAndroid Build Coastguard Worker // Copyright 2024 The ChromiumOS Authors
2*1b4853f5SAndroid Build Coastguard Worker 
3*1b4853f5SAndroid Build Coastguard Worker use std::os::fd::BorrowedFd;
4*1b4853f5SAndroid Build Coastguard Worker 
5*1b4853f5SAndroid Build Coastguard Worker use thiserror::Error;
6*1b4853f5SAndroid Build Coastguard Worker 
7*1b4853f5SAndroid Build Coastguard Worker use crate::VirtioMediaHostMemoryMapper;
8*1b4853f5SAndroid Build Coastguard Worker 
9*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq)]
10*1b4853f5SAndroid Build Coastguard Worker pub struct MmapBufferMapping {
11*1b4853f5SAndroid Build Coastguard Worker     /// Number of times `mmap` has been performed for this buffer.
12*1b4853f5SAndroid Build Coastguard Worker     num_mappings: usize,
13*1b4853f5SAndroid Build Coastguard Worker     /// Guest address at which the buffer is currently mapped.
14*1b4853f5SAndroid Build Coastguard Worker     guest_addr: u64,
15*1b4853f5SAndroid Build Coastguard Worker     /// Whether the mapping of this buffer is read-only or read-write.
16*1b4853f5SAndroid Build Coastguard Worker     rw: bool,
17*1b4853f5SAndroid Build Coastguard Worker }
18*1b4853f5SAndroid Build Coastguard Worker 
19*1b4853f5SAndroid Build Coastguard Worker /// Information about a MMAP buffer.
20*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq)]
21*1b4853f5SAndroid Build Coastguard Worker pub struct MmapBuffer {
22*1b4853f5SAndroid Build Coastguard Worker     /// Start offset in the MMAP range of this buffer.
23*1b4853f5SAndroid Build Coastguard Worker     offset: u32,
24*1b4853f5SAndroid Build Coastguard Worker     /// Size of the buffer.
25*1b4853f5SAndroid Build Coastguard Worker     size: u32,
26*1b4853f5SAndroid Build Coastguard Worker     /// Whether this buffer is still registered, i.e. hasn't been deleted by the driver.
27*1b4853f5SAndroid Build Coastguard Worker     /// Unregistered buffers can still have active mappings, and are kept alive until their mapping
28*1b4853f5SAndroid Build Coastguard Worker     /// count reaches zero. However such buffers cannot be mapped anymore and take no space in the
29*1b4853f5SAndroid Build Coastguard Worker     /// MMAP range.
30*1b4853f5SAndroid Build Coastguard Worker     registered: bool,
31*1b4853f5SAndroid Build Coastguard Worker     /// Mapping information about this buffer, if the buffer is currently mapped into the guest.
32*1b4853f5SAndroid Build Coastguard Worker     mapping: Option<MmapBufferMapping>,
33*1b4853f5SAndroid Build Coastguard Worker }
34*1b4853f5SAndroid Build Coastguard Worker 
35*1b4853f5SAndroid Build Coastguard Worker impl MmapBuffer {
36*1b4853f5SAndroid Build Coastguard Worker     /// Returns a new instance of `MmapBuffer` with the given parameters, zero mappings and
37*1b4853f5SAndroid Build Coastguard Worker     /// a registered status.
new(offset: u32, size: u32) -> Self38*1b4853f5SAndroid Build Coastguard Worker     fn new(offset: u32, size: u32) -> Self {
39*1b4853f5SAndroid Build Coastguard Worker         Self {
40*1b4853f5SAndroid Build Coastguard Worker             offset,
41*1b4853f5SAndroid Build Coastguard Worker             size,
42*1b4853f5SAndroid Build Coastguard Worker             registered: true,
43*1b4853f5SAndroid Build Coastguard Worker             mapping: None,
44*1b4853f5SAndroid Build Coastguard Worker         }
45*1b4853f5SAndroid Build Coastguard Worker     }
46*1b4853f5SAndroid Build Coastguard Worker }
47*1b4853f5SAndroid Build Coastguard Worker 
48*1b4853f5SAndroid Build Coastguard Worker /// Range manager for MMAP buffers, using a host memory mapper.
49*1b4853f5SAndroid Build Coastguard Worker ///
50*1b4853f5SAndroid Build Coastguard Worker /// Devices that allocate MMAP buffers can register a buffer using [`Self::register_buffer`] and
51*1b4853f5SAndroid Build Coastguard Worker /// unregister them with [`Self::unregister_buffer`]. Registered buffers can then be mapped into the
52*1b4853f5SAndroid Build Coastguard Worker /// guest address space by calling [`Self::create_mapping`] on their offset. This will return the address
53*1b4853f5SAndroid Build Coastguard Worker /// of their guest mapping, which can then be accessed or used to unmap them with [`Self::remove_mapping`].
54*1b4853f5SAndroid Build Coastguard Worker pub struct MmapMappingManager<M: VirtioMediaHostMemoryMapper> {
55*1b4853f5SAndroid Build Coastguard Worker     /// Sorted MMAP space of the device. Each registered MMAP buffer takes the `[offset, size - 1]`
56*1b4853f5SAndroid Build Coastguard Worker     /// range in this space, which is sorted in order to be binary-searchable.
57*1b4853f5SAndroid Build Coastguard Worker     ///
58*1b4853f5SAndroid Build Coastguard Worker     /// Buffers that are unregistered but still mapped are still kept here, but do not take space
59*1b4853f5SAndroid Build Coastguard Worker     /// in the MMAP range (i.e. they are skipped during the binary search).
60*1b4853f5SAndroid Build Coastguard Worker     buffers: Vec<MmapBuffer>,
61*1b4853f5SAndroid Build Coastguard Worker     /// Memory mapper used to create buffer mappings.
62*1b4853f5SAndroid Build Coastguard Worker     mapper: M,
63*1b4853f5SAndroid Build Coastguard Worker }
64*1b4853f5SAndroid Build Coastguard Worker 
65*1b4853f5SAndroid Build Coastguard Worker impl<M: VirtioMediaHostMemoryMapper> From<M> for MmapMappingManager<M> {
from(mapper: M) -> Self66*1b4853f5SAndroid Build Coastguard Worker     fn from(mapper: M) -> Self {
67*1b4853f5SAndroid Build Coastguard Worker         Self {
68*1b4853f5SAndroid Build Coastguard Worker             buffers: Vec::new(),
69*1b4853f5SAndroid Build Coastguard Worker             mapper,
70*1b4853f5SAndroid Build Coastguard Worker         }
71*1b4853f5SAndroid Build Coastguard Worker     }
72*1b4853f5SAndroid Build Coastguard Worker }
73*1b4853f5SAndroid Build Coastguard Worker 
74*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, Error, PartialEq, Eq)]
75*1b4853f5SAndroid Build Coastguard Worker pub enum RegisterBufferError {
76*1b4853f5SAndroid Build Coastguard Worker     #[error("insufficient free space in the MMAP range")]
77*1b4853f5SAndroid Build Coastguard Worker     NoFreeSpace,
78*1b4853f5SAndroid Build Coastguard Worker     #[error("requested offset is already occupied")]
79*1b4853f5SAndroid Build Coastguard Worker     OffsetOccupied,
80*1b4853f5SAndroid Build Coastguard Worker     #[error("buffers of size 0 cannot be registered")]
81*1b4853f5SAndroid Build Coastguard Worker     EmptyBuffer,
82*1b4853f5SAndroid Build Coastguard Worker     #[error("buffer offset must be a multiple of the memory page size")]
83*1b4853f5SAndroid Build Coastguard Worker     UnalignedOffset,
84*1b4853f5SAndroid Build Coastguard Worker }
85*1b4853f5SAndroid Build Coastguard Worker 
86*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, Error, PartialEq, Eq)]
87*1b4853f5SAndroid Build Coastguard Worker pub enum CreateMappingError {
88*1b4853f5SAndroid Build Coastguard Worker     #[error("no buffer registered at the requested offset")]
89*1b4853f5SAndroid Build Coastguard Worker     InvalidOffset,
90*1b4853f5SAndroid Build Coastguard Worker     #[error("cannot create new mappings for unregistered buffers")]
91*1b4853f5SAndroid Build Coastguard Worker     UnregisteredBuffer,
92*1b4853f5SAndroid Build Coastguard Worker     #[error("requested mapping range goes outside the buffer")]
93*1b4853f5SAndroid Build Coastguard Worker     SizeOutOfBounds,
94*1b4853f5SAndroid Build Coastguard Worker     #[error("error while cloning the FD for the buffer")]
95*1b4853f5SAndroid Build Coastguard Worker     FdCloneFailure(std::io::ErrorKind),
96*1b4853f5SAndroid Build Coastguard Worker     #[error("error while mapping the buffer: {0}")]
97*1b4853f5SAndroid Build Coastguard Worker     MappingFailure(i32),
98*1b4853f5SAndroid Build Coastguard Worker     #[error("mapping requested with different permission from the old one")]
99*1b4853f5SAndroid Build Coastguard Worker     NonMatchingPermissions,
100*1b4853f5SAndroid Build Coastguard Worker }
101*1b4853f5SAndroid Build Coastguard Worker 
102*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, Error, PartialEq, Eq)]
103*1b4853f5SAndroid Build Coastguard Worker pub enum RemoveMappingError {
104*1b4853f5SAndroid Build Coastguard Worker     #[error("no buffer registered at the requested offset")]
105*1b4853f5SAndroid Build Coastguard Worker     InvalidOffset,
106*1b4853f5SAndroid Build Coastguard Worker }
107*1b4853f5SAndroid Build Coastguard Worker 
108*1b4853f5SAndroid Build Coastguard Worker const PAGE_SIZE: u32 = 0x1000;
109*1b4853f5SAndroid Build Coastguard Worker const PAGE_MASK: u32 = !(PAGE_SIZE - 1);
110*1b4853f5SAndroid Build Coastguard Worker 
111*1b4853f5SAndroid Build Coastguard Worker impl<M: VirtioMediaHostMemoryMapper> MmapMappingManager<M> {
112*1b4853f5SAndroid Build Coastguard Worker     /// Registers a new buffer at `offset`. If `offset` if `None`, then an offset is allocated and
113*1b4853f5SAndroid Build Coastguard Worker     /// returned.
114*1b4853f5SAndroid Build Coastguard Worker     ///
115*1b4853f5SAndroid Build Coastguard Worker     /// This method fails if the range is full, or if `offset` is `Some` and the requested offset
116*1b4853f5SAndroid Build Coastguard Worker     /// if already used by some other buffer. If `offset` is `Some` and the function succeed, then
117*1b4853f5SAndroid Build Coastguard Worker     /// the returned value is guaranteed to be the passed offset.
118*1b4853f5SAndroid Build Coastguard Worker     ///
119*1b4853f5SAndroid Build Coastguard Worker     /// Note that the ranges automatically allocated are of fixed size: only the offset of a
120*1b4853f5SAndroid Build Coastguard Worker     /// buffer is relevant when mapping it, not its size. Real V4L2 drivers also use this trick of
121*1b4853f5SAndroid Build Coastguard Worker     /// allocating ranges such that buffers appear to overlap. This is useful as the address space
122*1b4853f5SAndroid Build Coastguard Worker     /// is technically 32-bit, and we might need to use buffers which added size would not fit.
123*1b4853f5SAndroid Build Coastguard Worker     ///
124*1b4853f5SAndroid Build Coastguard Worker     /// TODO: we should recycle offsets, and further type `MmapMappingManager` so that only one
125*1b4853f5SAndroid Build Coastguard Worker     /// allocation type can be used per instance (fixed or dynamic).
register_buffer( &mut self, offset: Option<u32>, size: u32, ) -> Result<u32, RegisterBufferError>126*1b4853f5SAndroid Build Coastguard Worker     pub fn register_buffer(
127*1b4853f5SAndroid Build Coastguard Worker         &mut self,
128*1b4853f5SAndroid Build Coastguard Worker         offset: Option<u32>,
129*1b4853f5SAndroid Build Coastguard Worker         size: u32,
130*1b4853f5SAndroid Build Coastguard Worker     ) -> Result<u32, RegisterBufferError> {
131*1b4853f5SAndroid Build Coastguard Worker         let offset = offset.unwrap_or_else(|| {
132*1b4853f5SAndroid Build Coastguard Worker             self.buffers
133*1b4853f5SAndroid Build Coastguard Worker                 .last()
134*1b4853f5SAndroid Build Coastguard Worker                 // Align the start offset to the next page, or `register_buffer_by_offset` will
135*1b4853f5SAndroid Build Coastguard Worker                 // fail.
136*1b4853f5SAndroid Build Coastguard Worker                 .map(|b| ((b.offset + 1).next_multiple_of(PAGE_SIZE)))
137*1b4853f5SAndroid Build Coastguard Worker                 .unwrap_or(0)
138*1b4853f5SAndroid Build Coastguard Worker         });
139*1b4853f5SAndroid Build Coastguard Worker 
140*1b4853f5SAndroid Build Coastguard Worker         self.register_buffer_by_offset(offset, size)
141*1b4853f5SAndroid Build Coastguard Worker             .map(|()| offset)
142*1b4853f5SAndroid Build Coastguard Worker     }
143*1b4853f5SAndroid Build Coastguard Worker 
144*1b4853f5SAndroid Build Coastguard Worker     /// Unregisters the buffer previously registered at `offset`. Returns `true` if a buffer was
145*1b4853f5SAndroid Build Coastguard Worker     /// indeed registered as starting at `offset`, `false` otherwise.
unregister_buffer(&mut self, offset: u32) -> bool146*1b4853f5SAndroid Build Coastguard Worker     pub fn unregister_buffer(&mut self, offset: u32) -> bool {
147*1b4853f5SAndroid Build Coastguard Worker         match self.buffers.binary_search_by_key(&offset, |b| b.offset) {
148*1b4853f5SAndroid Build Coastguard Worker             Err(_) => false,
149*1b4853f5SAndroid Build Coastguard Worker             Ok(index) => {
150*1b4853f5SAndroid Build Coastguard Worker                 let buffer = &mut self.buffers[index];
151*1b4853f5SAndroid Build Coastguard Worker 
152*1b4853f5SAndroid Build Coastguard Worker                 buffer.registered = false;
153*1b4853f5SAndroid Build Coastguard Worker                 // If there is no mapping then the buffer can be removed from the MMAP range.
154*1b4853f5SAndroid Build Coastguard Worker                 if buffer.mapping.is_none() {
155*1b4853f5SAndroid Build Coastguard Worker                     self.buffers.remove(index);
156*1b4853f5SAndroid Build Coastguard Worker                 }
157*1b4853f5SAndroid Build Coastguard Worker 
158*1b4853f5SAndroid Build Coastguard Worker                 true
159*1b4853f5SAndroid Build Coastguard Worker             }
160*1b4853f5SAndroid Build Coastguard Worker         }
161*1b4853f5SAndroid Build Coastguard Worker     }
162*1b4853f5SAndroid Build Coastguard Worker 
163*1b4853f5SAndroid Build Coastguard Worker     // Register a new buffer of `size` at `offset`. Returns an error if `offset` is` already
164*1b4853f5SAndroid Build Coastguard Worker     // occupied by another buffer.
165*1b4853f5SAndroid Build Coastguard Worker     //
166*1b4853f5SAndroid Build Coastguard Worker     // `size` must be greater than `0` and `offset` must be a multiple of `PAGE_SIZE`.
register_buffer_by_offset( &mut self, offset: u32, size: u32, ) -> Result<(), RegisterBufferError>167*1b4853f5SAndroid Build Coastguard Worker     fn register_buffer_by_offset(
168*1b4853f5SAndroid Build Coastguard Worker         &mut self,
169*1b4853f5SAndroid Build Coastguard Worker         offset: u32,
170*1b4853f5SAndroid Build Coastguard Worker         size: u32,
171*1b4853f5SAndroid Build Coastguard Worker     ) -> Result<(), RegisterBufferError> {
172*1b4853f5SAndroid Build Coastguard Worker         if size == 0 {
173*1b4853f5SAndroid Build Coastguard Worker             return Err(RegisterBufferError::EmptyBuffer);
174*1b4853f5SAndroid Build Coastguard Worker         }
175*1b4853f5SAndroid Build Coastguard Worker         if offset & PAGE_MASK != offset {
176*1b4853f5SAndroid Build Coastguard Worker             return Err(RegisterBufferError::UnalignedOffset);
177*1b4853f5SAndroid Build Coastguard Worker         }
178*1b4853f5SAndroid Build Coastguard Worker 
179*1b4853f5SAndroid Build Coastguard Worker         // Check that `offset` is actually available.
180*1b4853f5SAndroid Build Coastguard Worker         match self.buffers.binary_search_by_key(&offset, |b| b.offset) {
181*1b4853f5SAndroid Build Coastguard Worker             // Already have a registered buffer at that very offset.
182*1b4853f5SAndroid Build Coastguard Worker             Ok(_) => Err(RegisterBufferError::OffsetOccupied),
183*1b4853f5SAndroid Build Coastguard Worker             Err(index) => {
184*1b4853f5SAndroid Build Coastguard Worker                 self.buffers.insert(index, MmapBuffer::new(offset, size));
185*1b4853f5SAndroid Build Coastguard Worker                 Ok(())
186*1b4853f5SAndroid Build Coastguard Worker             }
187*1b4853f5SAndroid Build Coastguard Worker         }
188*1b4853f5SAndroid Build Coastguard Worker     }
189*1b4853f5SAndroid Build Coastguard Worker 
190*1b4853f5SAndroid Build Coastguard Worker     /// Create a new mapping for the buffer registered at `offset`. `rw` indicates whether the
191*1b4853f5SAndroid Build Coastguard Worker     /// mapping is read-only or read-write. Returns the guest address at which the buffer is
192*1b4853f5SAndroid Build Coastguard Worker     /// mapped, and the size of the mapping, which should be equal to the size of the buffer.
193*1b4853f5SAndroid Build Coastguard Worker     ///
194*1b4853f5SAndroid Build Coastguard Worker     /// This method can be called several times and will reuse the prior mapping if it exists. The
195*1b4853f5SAndroid Build Coastguard Worker     /// mapping will also persist until an identical number of calls to [`Self::remove_mapping`]
196*1b4853f5SAndroid Build Coastguard Worker     /// are performed.
197*1b4853f5SAndroid Build Coastguard Worker     ///
198*1b4853f5SAndroid Build Coastguard Worker     /// Note however that requiring the same active mapping with different `rw` permissions will
199*1b4853f5SAndroid Build Coastguard Worker     /// result in a `EPERM` error.
create_mapping( &mut self, offset: u32, fd: BorrowedFd, rw: bool, ) -> Result<(u64, u64), CreateMappingError>200*1b4853f5SAndroid Build Coastguard Worker     pub fn create_mapping(
201*1b4853f5SAndroid Build Coastguard Worker         &mut self,
202*1b4853f5SAndroid Build Coastguard Worker         offset: u32,
203*1b4853f5SAndroid Build Coastguard Worker         fd: BorrowedFd,
204*1b4853f5SAndroid Build Coastguard Worker         rw: bool,
205*1b4853f5SAndroid Build Coastguard Worker     ) -> Result<(u64, u64), CreateMappingError> {
206*1b4853f5SAndroid Build Coastguard Worker         let buffer = self
207*1b4853f5SAndroid Build Coastguard Worker             .buffers
208*1b4853f5SAndroid Build Coastguard Worker             .binary_search_by_key(&offset, |b| b.offset)
209*1b4853f5SAndroid Build Coastguard Worker             .map(|i| &mut self.buffers[i])
210*1b4853f5SAndroid Build Coastguard Worker             .map_err(|_| CreateMappingError::InvalidOffset)?;
211*1b4853f5SAndroid Build Coastguard Worker         let last_buffer_address = buffer
212*1b4853f5SAndroid Build Coastguard Worker             .offset
213*1b4853f5SAndroid Build Coastguard Worker             .checked_add(buffer.size - 1)
214*1b4853f5SAndroid Build Coastguard Worker             .ok_or(CreateMappingError::InvalidOffset)?;
215*1b4853f5SAndroid Build Coastguard Worker 
216*1b4853f5SAndroid Build Coastguard Worker         // Cannot create additional mappings for buffers that have been destroyed on the guest side.
217*1b4853f5SAndroid Build Coastguard Worker         if !buffer.registered {
218*1b4853f5SAndroid Build Coastguard Worker             return Err(CreateMappingError::UnregisteredBuffer);
219*1b4853f5SAndroid Build Coastguard Worker         }
220*1b4853f5SAndroid Build Coastguard Worker 
221*1b4853f5SAndroid Build Coastguard Worker         // Check that we are not requiring more mapping than the buffer can cover.
222*1b4853f5SAndroid Build Coastguard Worker         if last_buffer_address > buffer.offset + (buffer.size - 1) {
223*1b4853f5SAndroid Build Coastguard Worker             return Err(CreateMappingError::SizeOutOfBounds);
224*1b4853f5SAndroid Build Coastguard Worker         }
225*1b4853f5SAndroid Build Coastguard Worker 
226*1b4853f5SAndroid Build Coastguard Worker         let guest_addr = match &mut buffer.mapping {
227*1b4853f5SAndroid Build Coastguard Worker             None => {
228*1b4853f5SAndroid Build Coastguard Worker                 let guest_addr = self
229*1b4853f5SAndroid Build Coastguard Worker                     .mapper
230*1b4853f5SAndroid Build Coastguard Worker                     .add_mapping(
231*1b4853f5SAndroid Build Coastguard Worker                         fd,
232*1b4853f5SAndroid Build Coastguard Worker                         // Always map the full buffer so we can reuse the mapping even with different
233*1b4853f5SAndroid Build Coastguard Worker                         // sizes.
234*1b4853f5SAndroid Build Coastguard Worker                         buffer.size as u64,
235*1b4853f5SAndroid Build Coastguard Worker                         buffer.offset as u64,
236*1b4853f5SAndroid Build Coastguard Worker                         rw,
237*1b4853f5SAndroid Build Coastguard Worker                     )
238*1b4853f5SAndroid Build Coastguard Worker                     .map_err(CreateMappingError::MappingFailure)?;
239*1b4853f5SAndroid Build Coastguard Worker 
240*1b4853f5SAndroid Build Coastguard Worker                 buffer.mapping = Some(MmapBufferMapping {
241*1b4853f5SAndroid Build Coastguard Worker                     num_mappings: 1,
242*1b4853f5SAndroid Build Coastguard Worker                     rw,
243*1b4853f5SAndroid Build Coastguard Worker                     guest_addr,
244*1b4853f5SAndroid Build Coastguard Worker                 });
245*1b4853f5SAndroid Build Coastguard Worker 
246*1b4853f5SAndroid Build Coastguard Worker                 // TODO: need to be able to lookup the buffer back by guest address - add a
247*1b4853f5SAndroid Build Coastguard Worker                 // guest_addr -> offset table?
248*1b4853f5SAndroid Build Coastguard Worker                 guest_addr
249*1b4853f5SAndroid Build Coastguard Worker             }
250*1b4853f5SAndroid Build Coastguard Worker             Some(mapping) => {
251*1b4853f5SAndroid Build Coastguard Worker                 if mapping.rw != rw {
252*1b4853f5SAndroid Build Coastguard Worker                     return Err(CreateMappingError::NonMatchingPermissions);
253*1b4853f5SAndroid Build Coastguard Worker                 }
254*1b4853f5SAndroid Build Coastguard Worker                 mapping.num_mappings += 1;
255*1b4853f5SAndroid Build Coastguard Worker                 mapping.guest_addr
256*1b4853f5SAndroid Build Coastguard Worker             }
257*1b4853f5SAndroid Build Coastguard Worker         };
258*1b4853f5SAndroid Build Coastguard Worker 
259*1b4853f5SAndroid Build Coastguard Worker         Ok((guest_addr, buffer.size as u64))
260*1b4853f5SAndroid Build Coastguard Worker     }
261*1b4853f5SAndroid Build Coastguard Worker 
262*1b4853f5SAndroid Build Coastguard Worker     /// Returns `true` if the buffer still has other mappings, `false` if this was the last mapping.
remove_mapping(&mut self, guest_addr: u64) -> Result<bool, RemoveMappingError>263*1b4853f5SAndroid Build Coastguard Worker     pub fn remove_mapping(&mut self, guest_addr: u64) -> Result<bool, RemoveMappingError> {
264*1b4853f5SAndroid Build Coastguard Worker         // TODO: use a guest_addr -> offset table to avoid O(n) here?
265*1b4853f5SAndroid Build Coastguard Worker         for (i, buffer) in self.buffers.iter_mut().enumerate() {
266*1b4853f5SAndroid Build Coastguard Worker             match &mut buffer.mapping {
267*1b4853f5SAndroid Build Coastguard Worker                 Some(mapping) if mapping.guest_addr == guest_addr => {
268*1b4853f5SAndroid Build Coastguard Worker                     mapping.num_mappings -= 1;
269*1b4853f5SAndroid Build Coastguard Worker                     if mapping.num_mappings == 0 {
270*1b4853f5SAndroid Build Coastguard Worker                         if let Err(e) = self.mapper.remove_mapping(guest_addr) {
271*1b4853f5SAndroid Build Coastguard Worker                             log::error!("error while unmapping MMAP buffer: {:#}", e);
272*1b4853f5SAndroid Build Coastguard Worker                         }
273*1b4853f5SAndroid Build Coastguard Worker                         buffer.mapping = None;
274*1b4853f5SAndroid Build Coastguard Worker                         // If this was the last dangling mapping then the buffer can be removed
275*1b4853f5SAndroid Build Coastguard Worker                         // from the MMAP range.
276*1b4853f5SAndroid Build Coastguard Worker                         if !buffer.registered {
277*1b4853f5SAndroid Build Coastguard Worker                             self.buffers.remove(i);
278*1b4853f5SAndroid Build Coastguard Worker                         }
279*1b4853f5SAndroid Build Coastguard Worker                         return Ok(false);
280*1b4853f5SAndroid Build Coastguard Worker                     } else {
281*1b4853f5SAndroid Build Coastguard Worker                         return Ok(true);
282*1b4853f5SAndroid Build Coastguard Worker                     }
283*1b4853f5SAndroid Build Coastguard Worker                 }
284*1b4853f5SAndroid Build Coastguard Worker                 _ => (),
285*1b4853f5SAndroid Build Coastguard Worker             }
286*1b4853f5SAndroid Build Coastguard Worker         }
287*1b4853f5SAndroid Build Coastguard Worker 
288*1b4853f5SAndroid Build Coastguard Worker         Err(RemoveMappingError::InvalidOffset)
289*1b4853f5SAndroid Build Coastguard Worker     }
290*1b4853f5SAndroid Build Coastguard Worker     /// Returns `true` if the buffer registered at `offset` is already mapped.
is_mapped(&self, offset: u64) -> bool291*1b4853f5SAndroid Build Coastguard Worker     pub fn is_mapped(&self, offset: u64) -> bool {
292*1b4853f5SAndroid Build Coastguard Worker         let Ok(offset) = u32::try_from(offset) else {
293*1b4853f5SAndroid Build Coastguard Worker             return false;
294*1b4853f5SAndroid Build Coastguard Worker         };
295*1b4853f5SAndroid Build Coastguard Worker 
296*1b4853f5SAndroid Build Coastguard Worker         match self.buffers.binary_search_by_key(&offset, |b| b.offset) {
297*1b4853f5SAndroid Build Coastguard Worker             Err(_) => false,
298*1b4853f5SAndroid Build Coastguard Worker             Ok(index) => self.buffers[index].mapping.is_some(),
299*1b4853f5SAndroid Build Coastguard Worker         }
300*1b4853f5SAndroid Build Coastguard Worker     }
301*1b4853f5SAndroid Build Coastguard Worker 
302*1b4853f5SAndroid Build Coastguard Worker     /// Consume the mapping manager and return the mapper it has been constructed from.
into_mapper(self) -> M303*1b4853f5SAndroid Build Coastguard Worker     pub fn into_mapper(self) -> M {
304*1b4853f5SAndroid Build Coastguard Worker         self.mapper
305*1b4853f5SAndroid Build Coastguard Worker     }
306*1b4853f5SAndroid Build Coastguard Worker }
307*1b4853f5SAndroid Build Coastguard Worker 
308*1b4853f5SAndroid Build Coastguard Worker #[cfg(test)]
309*1b4853f5SAndroid Build Coastguard Worker mod tests {
310*1b4853f5SAndroid Build Coastguard Worker     use std::fs::File;
311*1b4853f5SAndroid Build Coastguard Worker     use std::os::fd::AsFd;
312*1b4853f5SAndroid Build Coastguard Worker     use std::os::fd::BorrowedFd;
313*1b4853f5SAndroid Build Coastguard Worker     use std::os::fd::FromRawFd;
314*1b4853f5SAndroid Build Coastguard Worker 
315*1b4853f5SAndroid Build Coastguard Worker     use crate::VirtioMediaHostMemoryMapper;
316*1b4853f5SAndroid Build Coastguard Worker 
317*1b4853f5SAndroid Build Coastguard Worker     use super::CreateMappingError;
318*1b4853f5SAndroid Build Coastguard Worker     use super::MmapBuffer;
319*1b4853f5SAndroid Build Coastguard Worker     use super::MmapBufferMapping;
320*1b4853f5SAndroid Build Coastguard Worker     use super::MmapMappingManager;
321*1b4853f5SAndroid Build Coastguard Worker     use super::RegisterBufferError;
322*1b4853f5SAndroid Build Coastguard Worker     use super::RemoveMappingError;
323*1b4853f5SAndroid Build Coastguard Worker 
324*1b4853f5SAndroid Build Coastguard Worker     struct DummyHostMemoryMapper;
325*1b4853f5SAndroid Build Coastguard Worker 
326*1b4853f5SAndroid Build Coastguard Worker     impl VirtioMediaHostMemoryMapper for DummyHostMemoryMapper {
add_mapping( &mut self, _buffer: BorrowedFd, _length: u64, offset: u64, _rw: bool, ) -> Result<u64, i32>327*1b4853f5SAndroid Build Coastguard Worker         fn add_mapping(
328*1b4853f5SAndroid Build Coastguard Worker             &mut self,
329*1b4853f5SAndroid Build Coastguard Worker             _buffer: BorrowedFd,
330*1b4853f5SAndroid Build Coastguard Worker             _length: u64,
331*1b4853f5SAndroid Build Coastguard Worker             offset: u64,
332*1b4853f5SAndroid Build Coastguard Worker             _rw: bool,
333*1b4853f5SAndroid Build Coastguard Worker         ) -> Result<u64, i32> {
334*1b4853f5SAndroid Build Coastguard Worker             Ok(offset | 0x8000_0000)
335*1b4853f5SAndroid Build Coastguard Worker         }
336*1b4853f5SAndroid Build Coastguard Worker 
remove_mapping(&mut self, _guest_addr: u64) -> Result<(), i32>337*1b4853f5SAndroid Build Coastguard Worker         fn remove_mapping(&mut self, _guest_addr: u64) -> Result<(), i32> {
338*1b4853f5SAndroid Build Coastguard Worker             Ok(())
339*1b4853f5SAndroid Build Coastguard Worker         }
340*1b4853f5SAndroid Build Coastguard Worker     }
341*1b4853f5SAndroid Build Coastguard Worker 
342*1b4853f5SAndroid Build Coastguard Worker     #[test]
mmap_manager_register_by_offset()343*1b4853f5SAndroid Build Coastguard Worker     fn mmap_manager_register_by_offset() {
344*1b4853f5SAndroid Build Coastguard Worker         let mut mm = MmapMappingManager::from(DummyHostMemoryMapper);
345*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.buffers, vec![]);
346*1b4853f5SAndroid Build Coastguard Worker 
347*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer_by_offset(0x0, 0x1000), Ok(()));
348*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.buffers, vec![MmapBuffer::new(0x0, 0x1000)]);
349*1b4853f5SAndroid Build Coastguard Worker 
350*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer_by_offset(0x1000, 0x5000), Ok(()));
351*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
352*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
353*1b4853f5SAndroid Build Coastguard Worker             vec![
354*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
355*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
356*1b4853f5SAndroid Build Coastguard Worker             ]
357*1b4853f5SAndroid Build Coastguard Worker         );
358*1b4853f5SAndroid Build Coastguard Worker 
359*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer_by_offset(0xa000, 0x1000), Ok(()));
360*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
361*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
362*1b4853f5SAndroid Build Coastguard Worker             vec![
363*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
364*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
365*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
366*1b4853f5SAndroid Build Coastguard Worker             ]
367*1b4853f5SAndroid Build Coastguard Worker         );
368*1b4853f5SAndroid Build Coastguard Worker 
369*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer_by_offset(0x6000, 0x2000), Ok(()));
370*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
371*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
372*1b4853f5SAndroid Build Coastguard Worker             vec![
373*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
374*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
375*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x6000, 0x2000),
376*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
377*1b4853f5SAndroid Build Coastguard Worker             ]
378*1b4853f5SAndroid Build Coastguard Worker         );
379*1b4853f5SAndroid Build Coastguard Worker 
380*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
381*1b4853f5SAndroid Build Coastguard Worker             mm.register_buffer_by_offset(0x8000, 0x0),
382*1b4853f5SAndroid Build Coastguard Worker             Err(RegisterBufferError::EmptyBuffer)
383*1b4853f5SAndroid Build Coastguard Worker         );
384*1b4853f5SAndroid Build Coastguard Worker 
385*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
386*1b4853f5SAndroid Build Coastguard Worker             mm.register_buffer_by_offset(0x8100, 0x1000),
387*1b4853f5SAndroid Build Coastguard Worker             Err(RegisterBufferError::UnalignedOffset)
388*1b4853f5SAndroid Build Coastguard Worker         );
389*1b4853f5SAndroid Build Coastguard Worker 
390*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
391*1b4853f5SAndroid Build Coastguard Worker             mm.register_buffer_by_offset(0x0, 0x1000),
392*1b4853f5SAndroid Build Coastguard Worker             Err(RegisterBufferError::OffsetOccupied)
393*1b4853f5SAndroid Build Coastguard Worker         );
394*1b4853f5SAndroid Build Coastguard Worker 
395*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
396*1b4853f5SAndroid Build Coastguard Worker             mm.register_buffer_by_offset(0x1000, 0x1000),
397*1b4853f5SAndroid Build Coastguard Worker             Err(RegisterBufferError::OffsetOccupied)
398*1b4853f5SAndroid Build Coastguard Worker         );
399*1b4853f5SAndroid Build Coastguard Worker 
400*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer_by_offset(0x2000, 0x1000), Ok(()));
401*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
402*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
403*1b4853f5SAndroid Build Coastguard Worker             vec![
404*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
405*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
406*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
407*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x6000, 0x2000),
408*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
409*1b4853f5SAndroid Build Coastguard Worker             ]
410*1b4853f5SAndroid Build Coastguard Worker         );
411*1b4853f5SAndroid Build Coastguard Worker 
412*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer_by_offset(0x7000, 0x2000), Ok(()));
413*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
414*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
415*1b4853f5SAndroid Build Coastguard Worker             vec![
416*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
417*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
418*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
419*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x6000, 0x2000),
420*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
421*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
422*1b4853f5SAndroid Build Coastguard Worker             ]
423*1b4853f5SAndroid Build Coastguard Worker         );
424*1b4853f5SAndroid Build Coastguard Worker 
425*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer_by_offset(0x8000, 0x2000), Ok(()));
426*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
427*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
428*1b4853f5SAndroid Build Coastguard Worker             vec![
429*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
430*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
431*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
432*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x6000, 0x2000),
433*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
434*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x8000, 0x2000),
435*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
436*1b4853f5SAndroid Build Coastguard Worker             ]
437*1b4853f5SAndroid Build Coastguard Worker         );
438*1b4853f5SAndroid Build Coastguard Worker 
439*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer_by_offset(0xffff_f000, 0x1000), Ok(()));
440*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
441*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
442*1b4853f5SAndroid Build Coastguard Worker             vec![
443*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
444*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
445*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
446*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x6000, 0x2000),
447*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
448*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x8000, 0x2000),
449*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
450*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xffff_f000, 0x1000),
451*1b4853f5SAndroid Build Coastguard Worker             ]
452*1b4853f5SAndroid Build Coastguard Worker         );
453*1b4853f5SAndroid Build Coastguard Worker 
454*1b4853f5SAndroid Build Coastguard Worker         assert!(mm.unregister_buffer(0xffff_f000));
455*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
456*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
457*1b4853f5SAndroid Build Coastguard Worker             vec![
458*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
459*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
460*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
461*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x6000, 0x2000),
462*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
463*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x8000, 0x2000),
464*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
465*1b4853f5SAndroid Build Coastguard Worker             ]
466*1b4853f5SAndroid Build Coastguard Worker         );
467*1b4853f5SAndroid Build Coastguard Worker 
468*1b4853f5SAndroid Build Coastguard Worker         assert!(mm.unregister_buffer(0x6000));
469*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
470*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
471*1b4853f5SAndroid Build Coastguard Worker             vec![
472*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
473*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
474*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
475*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
476*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x8000, 0x2000),
477*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
478*1b4853f5SAndroid Build Coastguard Worker             ]
479*1b4853f5SAndroid Build Coastguard Worker         );
480*1b4853f5SAndroid Build Coastguard Worker 
481*1b4853f5SAndroid Build Coastguard Worker         assert!(!mm.unregister_buffer(0x6000));
482*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
483*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
484*1b4853f5SAndroid Build Coastguard Worker             vec![
485*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
486*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
487*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
488*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
489*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x8000, 0x2000),
490*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
491*1b4853f5SAndroid Build Coastguard Worker             ]
492*1b4853f5SAndroid Build Coastguard Worker         );
493*1b4853f5SAndroid Build Coastguard Worker 
494*1b4853f5SAndroid Build Coastguard Worker         assert!(!mm.unregister_buffer(0x8100));
495*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
496*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
497*1b4853f5SAndroid Build Coastguard Worker             vec![
498*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
499*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
500*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
501*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
502*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x8000, 0x2000),
503*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
504*1b4853f5SAndroid Build Coastguard Worker             ]
505*1b4853f5SAndroid Build Coastguard Worker         );
506*1b4853f5SAndroid Build Coastguard Worker 
507*1b4853f5SAndroid Build Coastguard Worker         assert!(mm.unregister_buffer(0x0));
508*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
509*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
510*1b4853f5SAndroid Build Coastguard Worker             vec![
511*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
512*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
513*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
514*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x8000, 0x2000),
515*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0xa000, 0x1000),
516*1b4853f5SAndroid Build Coastguard Worker             ]
517*1b4853f5SAndroid Build Coastguard Worker         );
518*1b4853f5SAndroid Build Coastguard Worker 
519*1b4853f5SAndroid Build Coastguard Worker         assert!(mm.unregister_buffer(0xa000));
520*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
521*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
522*1b4853f5SAndroid Build Coastguard Worker             vec![
523*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
524*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
525*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
526*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x8000, 0x2000),
527*1b4853f5SAndroid Build Coastguard Worker             ]
528*1b4853f5SAndroid Build Coastguard Worker         );
529*1b4853f5SAndroid Build Coastguard Worker 
530*1b4853f5SAndroid Build Coastguard Worker         assert!(mm.unregister_buffer(0x1000));
531*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
532*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
533*1b4853f5SAndroid Build Coastguard Worker             vec![
534*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
535*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
536*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x8000, 0x2000),
537*1b4853f5SAndroid Build Coastguard Worker             ]
538*1b4853f5SAndroid Build Coastguard Worker         );
539*1b4853f5SAndroid Build Coastguard Worker 
540*1b4853f5SAndroid Build Coastguard Worker         assert!(mm.unregister_buffer(0x8000));
541*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
542*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
543*1b4853f5SAndroid Build Coastguard Worker             vec![
544*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
545*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
546*1b4853f5SAndroid Build Coastguard Worker             ]
547*1b4853f5SAndroid Build Coastguard Worker         );
548*1b4853f5SAndroid Build Coastguard Worker 
549*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
550*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
551*1b4853f5SAndroid Build Coastguard Worker             vec![
552*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0x1000),
553*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x7000, 0x2000),
554*1b4853f5SAndroid Build Coastguard Worker             ]
555*1b4853f5SAndroid Build Coastguard Worker         );
556*1b4853f5SAndroid Build Coastguard Worker     }
557*1b4853f5SAndroid Build Coastguard Worker 
558*1b4853f5SAndroid Build Coastguard Worker     #[test]
mmap_manager_register()559*1b4853f5SAndroid Build Coastguard Worker     fn mmap_manager_register() {
560*1b4853f5SAndroid Build Coastguard Worker         let mut mm = MmapMappingManager::from(DummyHostMemoryMapper);
561*1b4853f5SAndroid Build Coastguard Worker 
562*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer(None, 0x1000), Ok(0x0));
563*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.buffers, vec![MmapBuffer::new(0x0, 0x1000)]);
564*1b4853f5SAndroid Build Coastguard Worker 
565*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer(None, 0x5000), Ok(0x1000));
566*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
567*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
568*1b4853f5SAndroid Build Coastguard Worker             vec![
569*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
570*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
571*1b4853f5SAndroid Build Coastguard Worker             ]
572*1b4853f5SAndroid Build Coastguard Worker         );
573*1b4853f5SAndroid Build Coastguard Worker 
574*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer(None, 0xffff_a000), Ok(0x2000));
575*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
576*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
577*1b4853f5SAndroid Build Coastguard Worker             vec![
578*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
579*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
580*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0xffff_a000),
581*1b4853f5SAndroid Build Coastguard Worker             ]
582*1b4853f5SAndroid Build Coastguard Worker         );
583*1b4853f5SAndroid Build Coastguard Worker 
584*1b4853f5SAndroid Build Coastguard Worker         assert!(mm.unregister_buffer(0x2000));
585*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
586*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
587*1b4853f5SAndroid Build Coastguard Worker             vec![
588*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
589*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
590*1b4853f5SAndroid Build Coastguard Worker             ]
591*1b4853f5SAndroid Build Coastguard Worker         );
592*1b4853f5SAndroid Build Coastguard Worker 
593*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer(None, 0xffff_b000), Ok(0x2000));
594*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
595*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
596*1b4853f5SAndroid Build Coastguard Worker             vec![
597*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
598*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
599*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x2000, 0xffff_b000),
600*1b4853f5SAndroid Build Coastguard Worker             ]
601*1b4853f5SAndroid Build Coastguard Worker         );
602*1b4853f5SAndroid Build Coastguard Worker     }
603*1b4853f5SAndroid Build Coastguard Worker 
604*1b4853f5SAndroid Build Coastguard Worker     #[test]
mmap_manager_mapping()605*1b4853f5SAndroid Build Coastguard Worker     fn mmap_manager_mapping() {
606*1b4853f5SAndroid Build Coastguard Worker         let mut mm = MmapMappingManager::from(DummyHostMemoryMapper);
607*1b4853f5SAndroid Build Coastguard Worker 
608*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer(None, 0x1000), Ok(0x0));
609*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.register_buffer(None, 0x5000), Ok(0x1000));
610*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
611*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
612*1b4853f5SAndroid Build Coastguard Worker             vec![
613*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
614*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x1000, 0x5000),
615*1b4853f5SAndroid Build Coastguard Worker             ]
616*1b4853f5SAndroid Build Coastguard Worker         );
617*1b4853f5SAndroid Build Coastguard Worker 
618*1b4853f5SAndroid Build Coastguard Worker         let file = unsafe { File::from_raw_fd(0) };
619*1b4853f5SAndroid Build Coastguard Worker 
620*1b4853f5SAndroid Build Coastguard Worker         // Single mapping
621*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
622*1b4853f5SAndroid Build Coastguard Worker             mm.create_mapping(0x1000, file.as_fd(), false),
623*1b4853f5SAndroid Build Coastguard Worker             Ok((0x8000_1000, 0x5000))
624*1b4853f5SAndroid Build Coastguard Worker         );
625*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(false));
626*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
627*1b4853f5SAndroid Build Coastguard Worker             mm.remove_mapping(0x8000_1000),
628*1b4853f5SAndroid Build Coastguard Worker             Err(RemoveMappingError::InvalidOffset)
629*1b4853f5SAndroid Build Coastguard Worker         );
630*1b4853f5SAndroid Build Coastguard Worker 
631*1b4853f5SAndroid Build Coastguard Worker         // Multiple mappings
632*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
633*1b4853f5SAndroid Build Coastguard Worker             mm.create_mapping(0x1000, file.as_fd(), false),
634*1b4853f5SAndroid Build Coastguard Worker             Ok((0x8000_1000, 0x5000))
635*1b4853f5SAndroid Build Coastguard Worker         );
636*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
637*1b4853f5SAndroid Build Coastguard Worker             mm.create_mapping(0x1000, file.as_fd(), false),
638*1b4853f5SAndroid Build Coastguard Worker             Ok((0x8000_1000, 0x5000))
639*1b4853f5SAndroid Build Coastguard Worker         );
640*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(true));
641*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(false));
642*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
643*1b4853f5SAndroid Build Coastguard Worker             mm.remove_mapping(0x8000_1000),
644*1b4853f5SAndroid Build Coastguard Worker             Err(RemoveMappingError::InvalidOffset)
645*1b4853f5SAndroid Build Coastguard Worker         );
646*1b4853f5SAndroid Build Coastguard Worker 
647*1b4853f5SAndroid Build Coastguard Worker         // Mapping at non-existing offset
648*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
649*1b4853f5SAndroid Build Coastguard Worker             mm.create_mapping(0x2000, file.as_fd(), false),
650*1b4853f5SAndroid Build Coastguard Worker             Err(CreateMappingError::InvalidOffset)
651*1b4853f5SAndroid Build Coastguard Worker         );
652*1b4853f5SAndroid Build Coastguard Worker 
653*1b4853f5SAndroid Build Coastguard Worker         // Requesting same mapping with different access
654*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
655*1b4853f5SAndroid Build Coastguard Worker             mm.create_mapping(0x1000, file.as_fd(), false),
656*1b4853f5SAndroid Build Coastguard Worker             Ok((0x8000_1000, 0x5000))
657*1b4853f5SAndroid Build Coastguard Worker         );
658*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
659*1b4853f5SAndroid Build Coastguard Worker             mm.create_mapping(0x1000, file.as_fd(), true),
660*1b4853f5SAndroid Build Coastguard Worker             Err(CreateMappingError::NonMatchingPermissions)
661*1b4853f5SAndroid Build Coastguard Worker         );
662*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(false));
663*1b4853f5SAndroid Build Coastguard Worker 
664*1b4853f5SAndroid Build Coastguard Worker         // Mappings must survive a buffer's deregistration
665*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
666*1b4853f5SAndroid Build Coastguard Worker             mm.create_mapping(0x1000, file.as_fd(), false),
667*1b4853f5SAndroid Build Coastguard Worker             Ok((0x8000_1000, 0x5000))
668*1b4853f5SAndroid Build Coastguard Worker         );
669*1b4853f5SAndroid Build Coastguard Worker         assert!(mm.unregister_buffer(0x1000));
670*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(
671*1b4853f5SAndroid Build Coastguard Worker             mm.buffers,
672*1b4853f5SAndroid Build Coastguard Worker             vec![
673*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer::new(0x0, 0x1000),
674*1b4853f5SAndroid Build Coastguard Worker                 MmapBuffer {
675*1b4853f5SAndroid Build Coastguard Worker                     offset: 0x1000,
676*1b4853f5SAndroid Build Coastguard Worker                     size: 0x5000,
677*1b4853f5SAndroid Build Coastguard Worker                     registered: false,
678*1b4853f5SAndroid Build Coastguard Worker                     mapping: Some(MmapBufferMapping {
679*1b4853f5SAndroid Build Coastguard Worker                         num_mappings: 1,
680*1b4853f5SAndroid Build Coastguard Worker                         guest_addr: 0x8000_1000,
681*1b4853f5SAndroid Build Coastguard Worker                         rw: false
682*1b4853f5SAndroid Build Coastguard Worker                     })
683*1b4853f5SAndroid Build Coastguard Worker                 }
684*1b4853f5SAndroid Build Coastguard Worker             ]
685*1b4853f5SAndroid Build Coastguard Worker         );
686*1b4853f5SAndroid Build Coastguard Worker         // ... but un-registered buffers are removed alongside their last mapping.
687*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(false));
688*1b4853f5SAndroid Build Coastguard Worker         assert_eq!(mm.buffers, vec![MmapBuffer::new(0x0, 0x1000),])
689*1b4853f5SAndroid Build Coastguard Worker     }
690*1b4853f5SAndroid Build Coastguard Worker }
691