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