1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2021 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker //! Resource management and resolution for the virtio-video device. 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryInto; 8*bb4ee6a4SAndroid Build Coastguard Worker use std::fmt; 9*bb4ee6a4SAndroid Build Coastguard Worker 10*bb4ee6a4SAndroid Build Coastguard Worker use base::linux::MemoryMappingBuilderUnix; 11*bb4ee6a4SAndroid Build Coastguard Worker use base::FromRawDescriptor; 12*bb4ee6a4SAndroid Build Coastguard Worker use base::IntoRawDescriptor; 13*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingArena; 14*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingBuilder; 15*bb4ee6a4SAndroid Build Coastguard Worker use base::MmapError; 16*bb4ee6a4SAndroid Build Coastguard Worker use base::SafeDescriptor; 17*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError; 18*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress; 19*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory; 20*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemoryError; 21*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes; 22*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes; 23*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes; 24*bb4ee6a4SAndroid Build Coastguard Worker 25*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::resource_bridge; 26*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::resource_bridge::ResourceBridgeError; 27*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::resource_bridge::ResourceInfo; 28*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::resource_bridge::ResourceRequest; 29*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::video::format::Format; 30*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::video::format::FramePlane; 31*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::video::params::Params; 32*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::video::protocol::virtio_video_mem_entry; 33*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::video::protocol::virtio_video_object_entry; 34*bb4ee6a4SAndroid Build Coastguard Worker 35*bb4ee6a4SAndroid Build Coastguard Worker /// Defines how resources for a given queue are represented. 36*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] 37*bb4ee6a4SAndroid Build Coastguard Worker pub enum ResourceType { 38*bb4ee6a4SAndroid Build Coastguard Worker /// Resources are backed by guest memory pages. 39*bb4ee6a4SAndroid Build Coastguard Worker GuestPages, 40*bb4ee6a4SAndroid Build Coastguard Worker /// Resources are backed by virtio objects. 41*bb4ee6a4SAndroid Build Coastguard Worker #[default] 42*bb4ee6a4SAndroid Build Coastguard Worker VirtioObject, 43*bb4ee6a4SAndroid Build Coastguard Worker } 44*bb4ee6a4SAndroid Build Coastguard Worker 45*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)] 46*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, AsBytes, FromZeroes, FromBytes)] 47*bb4ee6a4SAndroid Build Coastguard Worker /// A guest resource entry which type is not decided yet. 48*bb4ee6a4SAndroid Build Coastguard Worker pub union UnresolvedResourceEntry { 49*bb4ee6a4SAndroid Build Coastguard Worker pub object: virtio_video_object_entry, 50*bb4ee6a4SAndroid Build Coastguard Worker pub guest_mem: virtio_video_mem_entry, 51*bb4ee6a4SAndroid Build Coastguard Worker } 52*bb4ee6a4SAndroid Build Coastguard Worker 53*bb4ee6a4SAndroid Build Coastguard Worker impl fmt::Debug for UnresolvedResourceEntry { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result54*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 55*bb4ee6a4SAndroid Build Coastguard Worker write!( 56*bb4ee6a4SAndroid Build Coastguard Worker f, 57*bb4ee6a4SAndroid Build Coastguard Worker "unresolved {:?} or {:?}", 58*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 59*bb4ee6a4SAndroid Build Coastguard Worker // Safe because `self.object` and `self.guest_mem` are the same size and both made of 60*bb4ee6a4SAndroid Build Coastguard Worker // integers, making it safe to display them no matter their value. 61*bb4ee6a4SAndroid Build Coastguard Worker unsafe { self.object }, 62*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 63*bb4ee6a4SAndroid Build Coastguard Worker // Safe because `self.object` and `self.guest_mem` are the same size and both made of 64*bb4ee6a4SAndroid Build Coastguard Worker // integers, making it safe to display them no matter their value. 65*bb4ee6a4SAndroid Build Coastguard Worker unsafe { self.guest_mem } 66*bb4ee6a4SAndroid Build Coastguard Worker ) 67*bb4ee6a4SAndroid Build Coastguard Worker } 68*bb4ee6a4SAndroid Build Coastguard Worker } 69*bb4ee6a4SAndroid Build Coastguard Worker 70*bb4ee6a4SAndroid Build Coastguard Worker /// Trait for types that can serve as video buffer backing memory. 71*bb4ee6a4SAndroid Build Coastguard Worker pub trait BufferHandle: Sized { 72*bb4ee6a4SAndroid Build Coastguard Worker /// Try to clone this handle. This must only create a new reference to the same backing memory 73*bb4ee6a4SAndroid Build Coastguard Worker /// and not duplicate the buffer itself. try_clone(&self) -> Result<Self, base::Error>74*bb4ee6a4SAndroid Build Coastguard Worker fn try_clone(&self) -> Result<Self, base::Error>; 75*bb4ee6a4SAndroid Build Coastguard Worker 76*bb4ee6a4SAndroid Build Coastguard Worker /// Returns a linear mapping of [`offset`..`offset`+`size`] of the memory backing this buffer. get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError>77*bb4ee6a4SAndroid Build Coastguard Worker fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError>; 78*bb4ee6a4SAndroid Build Coastguard Worker } 79*bb4ee6a4SAndroid Build Coastguard Worker 80*bb4ee6a4SAndroid Build Coastguard Worker /// Linear memory area of a `GuestMemHandle` 81*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone)] 82*bb4ee6a4SAndroid Build Coastguard Worker pub struct GuestMemArea { 83*bb4ee6a4SAndroid Build Coastguard Worker /// Offset within the guest region to the start of the area. 84*bb4ee6a4SAndroid Build Coastguard Worker pub offset: u64, 85*bb4ee6a4SAndroid Build Coastguard Worker /// Length of the area within the memory region. 86*bb4ee6a4SAndroid Build Coastguard Worker pub length: usize, 87*bb4ee6a4SAndroid Build Coastguard Worker } 88*bb4ee6a4SAndroid Build Coastguard Worker 89*bb4ee6a4SAndroid Build Coastguard Worker pub struct GuestMemHandle { 90*bb4ee6a4SAndroid Build Coastguard Worker /// Descriptor to the guest memory region containing the buffer. 91*bb4ee6a4SAndroid Build Coastguard Worker pub desc: SafeDescriptor, 92*bb4ee6a4SAndroid Build Coastguard Worker /// Memory areas (i.e. sg list) that make the memory buffer. 93*bb4ee6a4SAndroid Build Coastguard Worker pub mem_areas: Vec<GuestMemArea>, 94*bb4ee6a4SAndroid Build Coastguard Worker } 95*bb4ee6a4SAndroid Build Coastguard Worker 96*bb4ee6a4SAndroid Build Coastguard Worker impl BufferHandle for GuestMemHandle { try_clone(&self) -> Result<Self, base::Error>97*bb4ee6a4SAndroid Build Coastguard Worker fn try_clone(&self) -> Result<Self, base::Error> { 98*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self { 99*bb4ee6a4SAndroid Build Coastguard Worker desc: self.desc.try_clone()?, 100*bb4ee6a4SAndroid Build Coastguard Worker mem_areas: self.mem_areas.clone(), 101*bb4ee6a4SAndroid Build Coastguard Worker }) 102*bb4ee6a4SAndroid Build Coastguard Worker } 103*bb4ee6a4SAndroid Build Coastguard Worker get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError>104*bb4ee6a4SAndroid Build Coastguard Worker fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError> { 105*bb4ee6a4SAndroid Build Coastguard Worker let mut arena = MemoryMappingArena::new(size)?; 106*bb4ee6a4SAndroid Build Coastguard Worker let mut mapped_size = 0; 107*bb4ee6a4SAndroid Build Coastguard Worker let mut area_iter = self.mem_areas.iter(); 108*bb4ee6a4SAndroid Build Coastguard Worker let mut area_offset = offset; 109*bb4ee6a4SAndroid Build Coastguard Worker while mapped_size < size { 110*bb4ee6a4SAndroid Build Coastguard Worker let area = match area_iter.next() { 111*bb4ee6a4SAndroid Build Coastguard Worker Some(area) => area, 112*bb4ee6a4SAndroid Build Coastguard Worker None => { 113*bb4ee6a4SAndroid Build Coastguard Worker return Err(MmapError::InvalidRange( 114*bb4ee6a4SAndroid Build Coastguard Worker offset, 115*bb4ee6a4SAndroid Build Coastguard Worker size, 116*bb4ee6a4SAndroid Build Coastguard Worker self.mem_areas.iter().map(|a| a.length).sum(), 117*bb4ee6a4SAndroid Build Coastguard Worker )); 118*bb4ee6a4SAndroid Build Coastguard Worker } 119*bb4ee6a4SAndroid Build Coastguard Worker }; 120*bb4ee6a4SAndroid Build Coastguard Worker if area_offset > area.length { 121*bb4ee6a4SAndroid Build Coastguard Worker area_offset -= area.length; 122*bb4ee6a4SAndroid Build Coastguard Worker } else { 123*bb4ee6a4SAndroid Build Coastguard Worker let mapping_length = std::cmp::min(area.length - area_offset, size - mapped_size); 124*bb4ee6a4SAndroid Build Coastguard Worker arena.add_fd_offset(mapped_size, mapping_length, &self.desc, area.offset)?; 125*bb4ee6a4SAndroid Build Coastguard Worker mapped_size += mapping_length; 126*bb4ee6a4SAndroid Build Coastguard Worker area_offset = 0; 127*bb4ee6a4SAndroid Build Coastguard Worker } 128*bb4ee6a4SAndroid Build Coastguard Worker } 129*bb4ee6a4SAndroid Build Coastguard Worker Ok(arena) 130*bb4ee6a4SAndroid Build Coastguard Worker } 131*bb4ee6a4SAndroid Build Coastguard Worker } 132*bb4ee6a4SAndroid Build Coastguard Worker 133*bb4ee6a4SAndroid Build Coastguard Worker pub struct VirtioObjectHandle { 134*bb4ee6a4SAndroid Build Coastguard Worker /// Descriptor for the object. 135*bb4ee6a4SAndroid Build Coastguard Worker pub desc: SafeDescriptor, 136*bb4ee6a4SAndroid Build Coastguard Worker /// Modifier to apply to frame resources. 137*bb4ee6a4SAndroid Build Coastguard Worker pub modifier: u64, 138*bb4ee6a4SAndroid Build Coastguard Worker } 139*bb4ee6a4SAndroid Build Coastguard Worker 140*bb4ee6a4SAndroid Build Coastguard Worker impl BufferHandle for VirtioObjectHandle { try_clone(&self) -> Result<Self, base::Error>141*bb4ee6a4SAndroid Build Coastguard Worker fn try_clone(&self) -> Result<Self, base::Error> { 142*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self { 143*bb4ee6a4SAndroid Build Coastguard Worker desc: self.desc.try_clone()?, 144*bb4ee6a4SAndroid Build Coastguard Worker modifier: self.modifier, 145*bb4ee6a4SAndroid Build Coastguard Worker }) 146*bb4ee6a4SAndroid Build Coastguard Worker } 147*bb4ee6a4SAndroid Build Coastguard Worker get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError>148*bb4ee6a4SAndroid Build Coastguard Worker fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError> { 149*bb4ee6a4SAndroid Build Coastguard Worker MemoryMappingBuilder::new(size) 150*bb4ee6a4SAndroid Build Coastguard Worker .from_descriptor(&self.desc) 151*bb4ee6a4SAndroid Build Coastguard Worker .offset(offset as u64) 152*bb4ee6a4SAndroid Build Coastguard Worker .build() 153*bb4ee6a4SAndroid Build Coastguard Worker .map(MemoryMappingArena::from) 154*bb4ee6a4SAndroid Build Coastguard Worker } 155*bb4ee6a4SAndroid Build Coastguard Worker } 156*bb4ee6a4SAndroid Build Coastguard Worker 157*bb4ee6a4SAndroid Build Coastguard Worker pub enum GuestResourceHandle { 158*bb4ee6a4SAndroid Build Coastguard Worker GuestPages(GuestMemHandle), 159*bb4ee6a4SAndroid Build Coastguard Worker VirtioObject(VirtioObjectHandle), 160*bb4ee6a4SAndroid Build Coastguard Worker } 161*bb4ee6a4SAndroid Build Coastguard Worker 162*bb4ee6a4SAndroid Build Coastguard Worker impl BufferHandle for GuestResourceHandle { try_clone(&self) -> Result<Self, base::Error>163*bb4ee6a4SAndroid Build Coastguard Worker fn try_clone(&self) -> Result<Self, base::Error> { 164*bb4ee6a4SAndroid Build Coastguard Worker Ok(match self { 165*bb4ee6a4SAndroid Build Coastguard Worker Self::GuestPages(handle) => Self::GuestPages(handle.try_clone()?), 166*bb4ee6a4SAndroid Build Coastguard Worker Self::VirtioObject(handle) => Self::VirtioObject(handle.try_clone()?), 167*bb4ee6a4SAndroid Build Coastguard Worker }) 168*bb4ee6a4SAndroid Build Coastguard Worker } 169*bb4ee6a4SAndroid Build Coastguard Worker get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError>170*bb4ee6a4SAndroid Build Coastguard Worker fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError> { 171*bb4ee6a4SAndroid Build Coastguard Worker match self { 172*bb4ee6a4SAndroid Build Coastguard Worker GuestResourceHandle::GuestPages(handle) => handle.get_mapping(offset, size), 173*bb4ee6a4SAndroid Build Coastguard Worker GuestResourceHandle::VirtioObject(handle) => handle.get_mapping(offset, size), 174*bb4ee6a4SAndroid Build Coastguard Worker } 175*bb4ee6a4SAndroid Build Coastguard Worker } 176*bb4ee6a4SAndroid Build Coastguard Worker } 177*bb4ee6a4SAndroid Build Coastguard Worker 178*bb4ee6a4SAndroid Build Coastguard Worker pub struct GuestResource { 179*bb4ee6a4SAndroid Build Coastguard Worker /// Handle to the backing memory. 180*bb4ee6a4SAndroid Build Coastguard Worker pub handle: GuestResourceHandle, 181*bb4ee6a4SAndroid Build Coastguard Worker /// Layout of color planes, if the resource will receive frames. 182*bb4ee6a4SAndroid Build Coastguard Worker pub planes: Vec<FramePlane>, 183*bb4ee6a4SAndroid Build Coastguard Worker pub width: u32, 184*bb4ee6a4SAndroid Build Coastguard Worker pub height: u32, 185*bb4ee6a4SAndroid Build Coastguard Worker pub format: Format, 186*bb4ee6a4SAndroid Build Coastguard Worker /// Whether the buffer can be accessed by the guest CPU. This means the host must ensure that 187*bb4ee6a4SAndroid Build Coastguard Worker /// all operations on the buffer are completed before passing it to the guest. 188*bb4ee6a4SAndroid Build Coastguard Worker pub guest_cpu_mappable: bool, 189*bb4ee6a4SAndroid Build Coastguard Worker } 190*bb4ee6a4SAndroid Build Coastguard Worker 191*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, ThisError)] 192*bb4ee6a4SAndroid Build Coastguard Worker pub enum GuestMemResourceCreationError { 193*bb4ee6a4SAndroid Build Coastguard Worker #[error("Provided slice of entries is empty")] 194*bb4ee6a4SAndroid Build Coastguard Worker NoEntriesProvided, 195*bb4ee6a4SAndroid Build Coastguard Worker #[error("cannot get shm region: {0}")] 196*bb4ee6a4SAndroid Build Coastguard Worker CantGetShmRegion(GuestMemoryError), 197*bb4ee6a4SAndroid Build Coastguard Worker #[error("cannot get shm offset: {0}")] 198*bb4ee6a4SAndroid Build Coastguard Worker CantGetShmOffset(GuestMemoryError), 199*bb4ee6a4SAndroid Build Coastguard Worker #[error("error while cloning shm region descriptor: {0}")] 200*bb4ee6a4SAndroid Build Coastguard Worker DescriptorCloneError(base::Error), 201*bb4ee6a4SAndroid Build Coastguard Worker } 202*bb4ee6a4SAndroid Build Coastguard Worker 203*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, ThisError)] 204*bb4ee6a4SAndroid Build Coastguard Worker pub enum ObjectResourceCreationError { 205*bb4ee6a4SAndroid Build Coastguard Worker #[error("uuid {0:08} is larger than 32 bits")] 206*bb4ee6a4SAndroid Build Coastguard Worker UuidNot32Bits(u128), 207*bb4ee6a4SAndroid Build Coastguard Worker #[error("resource returned by bridge is not a buffer")] 208*bb4ee6a4SAndroid Build Coastguard Worker NotABuffer, 209*bb4ee6a4SAndroid Build Coastguard Worker #[error("resource bridge failure: {0}")] 210*bb4ee6a4SAndroid Build Coastguard Worker ResourceBridgeFailure(ResourceBridgeError), 211*bb4ee6a4SAndroid Build Coastguard Worker } 212*bb4ee6a4SAndroid Build Coastguard Worker 213*bb4ee6a4SAndroid Build Coastguard Worker impl GuestResource { 214*bb4ee6a4SAndroid Build Coastguard Worker /// Try to convert an unresolved virtio guest memory entry into a resolved guest memory 215*bb4ee6a4SAndroid Build Coastguard Worker /// resource. 216*bb4ee6a4SAndroid Build Coastguard Worker /// 217*bb4ee6a4SAndroid Build Coastguard Worker /// Convert `mem_entry` into the guest memory resource it represents and resolve it through 218*bb4ee6a4SAndroid Build Coastguard Worker /// `mem`. 219*bb4ee6a4SAndroid Build Coastguard Worker /// Width, height and format is set from `params`. 220*bb4ee6a4SAndroid Build Coastguard Worker /// 221*bb4ee6a4SAndroid Build Coastguard Worker /// Panics if `params.format` is `None`. from_virtio_guest_mem_entry( mem_entries: &[virtio_video_mem_entry], mem: &GuestMemory, params: &Params, ) -> Result<GuestResource, GuestMemResourceCreationError>222*bb4ee6a4SAndroid Build Coastguard Worker pub fn from_virtio_guest_mem_entry( 223*bb4ee6a4SAndroid Build Coastguard Worker mem_entries: &[virtio_video_mem_entry], 224*bb4ee6a4SAndroid Build Coastguard Worker mem: &GuestMemory, 225*bb4ee6a4SAndroid Build Coastguard Worker params: &Params, 226*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<GuestResource, GuestMemResourceCreationError> { 227*bb4ee6a4SAndroid Build Coastguard Worker let region_desc = match mem_entries.first() { 228*bb4ee6a4SAndroid Build Coastguard Worker None => return Err(GuestMemResourceCreationError::NoEntriesProvided), 229*bb4ee6a4SAndroid Build Coastguard Worker Some(entry) => { 230*bb4ee6a4SAndroid Build Coastguard Worker let addr: u64 = entry.addr.into(); 231*bb4ee6a4SAndroid Build Coastguard Worker 232*bb4ee6a4SAndroid Build Coastguard Worker let guest_region = mem 233*bb4ee6a4SAndroid Build Coastguard Worker .shm_region(GuestAddress(addr)) 234*bb4ee6a4SAndroid Build Coastguard Worker .map_err(GuestMemResourceCreationError::CantGetShmRegion)?; 235*bb4ee6a4SAndroid Build Coastguard Worker base::clone_descriptor(guest_region) 236*bb4ee6a4SAndroid Build Coastguard Worker .map_err(GuestMemResourceCreationError::DescriptorCloneError)? 237*bb4ee6a4SAndroid Build Coastguard Worker } 238*bb4ee6a4SAndroid Build Coastguard Worker }; 239*bb4ee6a4SAndroid Build Coastguard Worker 240*bb4ee6a4SAndroid Build Coastguard Worker let mem_areas = mem_entries 241*bb4ee6a4SAndroid Build Coastguard Worker .iter() 242*bb4ee6a4SAndroid Build Coastguard Worker .map(|entry| { 243*bb4ee6a4SAndroid Build Coastguard Worker let addr: u64 = entry.addr.into(); 244*bb4ee6a4SAndroid Build Coastguard Worker let length: u32 = entry.length.into(); 245*bb4ee6a4SAndroid Build Coastguard Worker let region_offset = mem 246*bb4ee6a4SAndroid Build Coastguard Worker .offset_from_base(GuestAddress(addr)) 247*bb4ee6a4SAndroid Build Coastguard Worker .map_err(GuestMemResourceCreationError::CantGetShmOffset) 248*bb4ee6a4SAndroid Build Coastguard Worker .unwrap(); 249*bb4ee6a4SAndroid Build Coastguard Worker 250*bb4ee6a4SAndroid Build Coastguard Worker GuestMemArea { 251*bb4ee6a4SAndroid Build Coastguard Worker offset: region_offset, 252*bb4ee6a4SAndroid Build Coastguard Worker length: length as usize, 253*bb4ee6a4SAndroid Build Coastguard Worker } 254*bb4ee6a4SAndroid Build Coastguard Worker }) 255*bb4ee6a4SAndroid Build Coastguard Worker .collect(); 256*bb4ee6a4SAndroid Build Coastguard Worker 257*bb4ee6a4SAndroid Build Coastguard Worker let handle = GuestResourceHandle::GuestPages(GuestMemHandle { 258*bb4ee6a4SAndroid Build Coastguard Worker desc: region_desc, 259*bb4ee6a4SAndroid Build Coastguard Worker mem_areas, 260*bb4ee6a4SAndroid Build Coastguard Worker }); 261*bb4ee6a4SAndroid Build Coastguard Worker 262*bb4ee6a4SAndroid Build Coastguard Worker // The plane information can be computed from the currently set format. 263*bb4ee6a4SAndroid Build Coastguard Worker let mut buffer_offset = 0; 264*bb4ee6a4SAndroid Build Coastguard Worker let planes = params 265*bb4ee6a4SAndroid Build Coastguard Worker .plane_formats 266*bb4ee6a4SAndroid Build Coastguard Worker .iter() 267*bb4ee6a4SAndroid Build Coastguard Worker .map(|p| { 268*bb4ee6a4SAndroid Build Coastguard Worker let plane_offset = buffer_offset; 269*bb4ee6a4SAndroid Build Coastguard Worker buffer_offset += p.plane_size; 270*bb4ee6a4SAndroid Build Coastguard Worker 271*bb4ee6a4SAndroid Build Coastguard Worker FramePlane { 272*bb4ee6a4SAndroid Build Coastguard Worker offset: plane_offset as usize, 273*bb4ee6a4SAndroid Build Coastguard Worker stride: p.stride as usize, 274*bb4ee6a4SAndroid Build Coastguard Worker size: p.plane_size as usize, 275*bb4ee6a4SAndroid Build Coastguard Worker } 276*bb4ee6a4SAndroid Build Coastguard Worker }) 277*bb4ee6a4SAndroid Build Coastguard Worker .collect(); 278*bb4ee6a4SAndroid Build Coastguard Worker 279*bb4ee6a4SAndroid Build Coastguard Worker Ok(GuestResource { 280*bb4ee6a4SAndroid Build Coastguard Worker handle, 281*bb4ee6a4SAndroid Build Coastguard Worker planes, 282*bb4ee6a4SAndroid Build Coastguard Worker width: params.frame_width, 283*bb4ee6a4SAndroid Build Coastguard Worker height: params.frame_height, 284*bb4ee6a4SAndroid Build Coastguard Worker format: params.format.unwrap(), 285*bb4ee6a4SAndroid Build Coastguard Worker guest_cpu_mappable: true, 286*bb4ee6a4SAndroid Build Coastguard Worker }) 287*bb4ee6a4SAndroid Build Coastguard Worker } 288*bb4ee6a4SAndroid Build Coastguard Worker 289*bb4ee6a4SAndroid Build Coastguard Worker /// Try to convert an unresolved virtio object entry into a resolved object resource. 290*bb4ee6a4SAndroid Build Coastguard Worker /// 291*bb4ee6a4SAndroid Build Coastguard Worker /// Convert `object` into the object resource it represents and resolve it through `res_bridge`. 292*bb4ee6a4SAndroid Build Coastguard Worker /// Returns an error if the object's UUID is invalid or cannot be resolved to a buffer object 293*bb4ee6a4SAndroid Build Coastguard Worker /// by `res_bridge`. from_virtio_object_entry( object: virtio_video_object_entry, res_bridge: &base::Tube, params: &Params, ) -> Result<GuestResource, ObjectResourceCreationError>294*bb4ee6a4SAndroid Build Coastguard Worker pub fn from_virtio_object_entry( 295*bb4ee6a4SAndroid Build Coastguard Worker object: virtio_video_object_entry, 296*bb4ee6a4SAndroid Build Coastguard Worker res_bridge: &base::Tube, 297*bb4ee6a4SAndroid Build Coastguard Worker params: &Params, 298*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<GuestResource, ObjectResourceCreationError> { 299*bb4ee6a4SAndroid Build Coastguard Worker // We trust that the caller has chosen the correct object type. 300*bb4ee6a4SAndroid Build Coastguard Worker let uuid = u128::from_be_bytes(object.uuid); 301*bb4ee6a4SAndroid Build Coastguard Worker 302*bb4ee6a4SAndroid Build Coastguard Worker // TODO(stevensd): `Virtio3DBackend::resource_assign_uuid` is currently implemented to use 303*bb4ee6a4SAndroid Build Coastguard Worker // 32-bits resource_handles as UUIDs. Once it starts using real UUIDs, we need to update 304*bb4ee6a4SAndroid Build Coastguard Worker // this conversion. 305*bb4ee6a4SAndroid Build Coastguard Worker let handle = TryInto::<u32>::try_into(uuid) 306*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| ObjectResourceCreationError::UuidNot32Bits(uuid))?; 307*bb4ee6a4SAndroid Build Coastguard Worker 308*bb4ee6a4SAndroid Build Coastguard Worker let buffer_info = match resource_bridge::get_resource_info( 309*bb4ee6a4SAndroid Build Coastguard Worker res_bridge, 310*bb4ee6a4SAndroid Build Coastguard Worker ResourceRequest::GetBuffer { id: handle }, 311*bb4ee6a4SAndroid Build Coastguard Worker ) { 312*bb4ee6a4SAndroid Build Coastguard Worker Ok(ResourceInfo::Buffer(buffer_info)) => buffer_info, 313*bb4ee6a4SAndroid Build Coastguard Worker Ok(_) => return Err(ObjectResourceCreationError::NotABuffer), 314*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => return Err(ObjectResourceCreationError::ResourceBridgeFailure(e)), 315*bb4ee6a4SAndroid Build Coastguard Worker }; 316*bb4ee6a4SAndroid Build Coastguard Worker 317*bb4ee6a4SAndroid Build Coastguard Worker let handle = GuestResourceHandle::VirtioObject(VirtioObjectHandle { 318*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 319*bb4ee6a4SAndroid Build Coastguard Worker // Safe because `buffer_info.file` is a valid file descriptor and we are stealing 320*bb4ee6a4SAndroid Build Coastguard Worker // it. 321*bb4ee6a4SAndroid Build Coastguard Worker desc: unsafe { 322*bb4ee6a4SAndroid Build Coastguard Worker SafeDescriptor::from_raw_descriptor(buffer_info.handle.into_raw_descriptor()) 323*bb4ee6a4SAndroid Build Coastguard Worker }, 324*bb4ee6a4SAndroid Build Coastguard Worker modifier: buffer_info.modifier, 325*bb4ee6a4SAndroid Build Coastguard Worker }); 326*bb4ee6a4SAndroid Build Coastguard Worker 327*bb4ee6a4SAndroid Build Coastguard Worker // TODO(ishitatsuyuki): Right now, there are two sources of metadata: through the 328*bb4ee6a4SAndroid Build Coastguard Worker // virtio_video_params fields, or through the buffer metadata provided 329*bb4ee6a4SAndroid Build Coastguard Worker // by the VirtioObject backend. 330*bb4ee6a4SAndroid Build Coastguard Worker // Unfortunately neither is sufficient. The virtio_video_params struct 331*bb4ee6a4SAndroid Build Coastguard Worker // lacks the plane offset, while some virtio-gpu backend doesn't 332*bb4ee6a4SAndroid Build Coastguard Worker // have information about the plane size, or in some cases even the 333*bb4ee6a4SAndroid Build Coastguard Worker // overall frame width and height. 334*bb4ee6a4SAndroid Build Coastguard Worker // We will mix-and-match metadata from the more reliable data source 335*bb4ee6a4SAndroid Build Coastguard Worker // below; ideally this should be fixed to use single source of truth. 336*bb4ee6a4SAndroid Build Coastguard Worker let planes = params 337*bb4ee6a4SAndroid Build Coastguard Worker .plane_formats 338*bb4ee6a4SAndroid Build Coastguard Worker .iter() 339*bb4ee6a4SAndroid Build Coastguard Worker .zip(&buffer_info.planes) 340*bb4ee6a4SAndroid Build Coastguard Worker .map(|(param, buffer)| FramePlane { 341*bb4ee6a4SAndroid Build Coastguard Worker // When the virtio object backend was implemented, the buffer and stride was sourced 342*bb4ee6a4SAndroid Build Coastguard Worker // from the object backend's metadata (`buffer`). To lean on the safe side, we'll 343*bb4ee6a4SAndroid Build Coastguard Worker // keep using data from `buffer`, even in case of stride it's also provided by 344*bb4ee6a4SAndroid Build Coastguard Worker // `param`. 345*bb4ee6a4SAndroid Build Coastguard Worker offset: buffer.offset as usize, 346*bb4ee6a4SAndroid Build Coastguard Worker stride: buffer.stride as usize, 347*bb4ee6a4SAndroid Build Coastguard Worker size: param.plane_size as usize, 348*bb4ee6a4SAndroid Build Coastguard Worker }) 349*bb4ee6a4SAndroid Build Coastguard Worker .collect(); 350*bb4ee6a4SAndroid Build Coastguard Worker 351*bb4ee6a4SAndroid Build Coastguard Worker Ok(GuestResource { 352*bb4ee6a4SAndroid Build Coastguard Worker handle, 353*bb4ee6a4SAndroid Build Coastguard Worker planes, 354*bb4ee6a4SAndroid Build Coastguard Worker width: params.frame_width, 355*bb4ee6a4SAndroid Build Coastguard Worker height: params.frame_height, 356*bb4ee6a4SAndroid Build Coastguard Worker format: params.format.unwrap(), 357*bb4ee6a4SAndroid Build Coastguard Worker guest_cpu_mappable: buffer_info.guest_cpu_mappable, 358*bb4ee6a4SAndroid Build Coastguard Worker }) 359*bb4ee6a4SAndroid Build Coastguard Worker } 360*bb4ee6a4SAndroid Build Coastguard Worker 361*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "video-encoder")] try_clone(&self) -> Result<Self, base::Error>362*bb4ee6a4SAndroid Build Coastguard Worker pub fn try_clone(&self) -> Result<Self, base::Error> { 363*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self { 364*bb4ee6a4SAndroid Build Coastguard Worker handle: self.handle.try_clone()?, 365*bb4ee6a4SAndroid Build Coastguard Worker planes: self.planes.clone(), 366*bb4ee6a4SAndroid Build Coastguard Worker width: self.width, 367*bb4ee6a4SAndroid Build Coastguard Worker height: self.height, 368*bb4ee6a4SAndroid Build Coastguard Worker format: self.format, 369*bb4ee6a4SAndroid Build Coastguard Worker guest_cpu_mappable: self.guest_cpu_mappable, 370*bb4ee6a4SAndroid Build Coastguard Worker }) 371*bb4ee6a4SAndroid Build Coastguard Worker } 372*bb4ee6a4SAndroid Build Coastguard Worker } 373*bb4ee6a4SAndroid Build Coastguard Worker 374*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)] 375*bb4ee6a4SAndroid Build Coastguard Worker mod tests { 376*bb4ee6a4SAndroid Build Coastguard Worker use base::MappedRegion; 377*bb4ee6a4SAndroid Build Coastguard Worker use base::SharedMemory; 378*bb4ee6a4SAndroid Build Coastguard Worker 379*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 380*bb4ee6a4SAndroid Build Coastguard Worker 381*bb4ee6a4SAndroid Build Coastguard Worker /// Creates a sparse guest memory handle using as many pages as there are entries in 382*bb4ee6a4SAndroid Build Coastguard Worker /// `page_order`. The page with index `0` will be the first page, `1` will be the second page, 383*bb4ee6a4SAndroid Build Coastguard Worker /// etc. 384*bb4ee6a4SAndroid Build Coastguard Worker /// 385*bb4ee6a4SAndroid Build Coastguard Worker /// The memory handle is filled with increasing u32s starting from page 0, then page 1, and so 386*bb4ee6a4SAndroid Build Coastguard Worker /// on. Finally the handle is mapped into a linear space and we check that the written integers 387*bb4ee6a4SAndroid Build Coastguard Worker /// appear in the expected order. check_guest_mem_handle(page_order: &[usize])388*bb4ee6a4SAndroid Build Coastguard Worker fn check_guest_mem_handle(page_order: &[usize]) { 389*bb4ee6a4SAndroid Build Coastguard Worker const PAGE_SIZE: usize = 0x1000; 390*bb4ee6a4SAndroid Build Coastguard Worker const U32_SIZE: usize = std::mem::size_of::<u32>(); 391*bb4ee6a4SAndroid Build Coastguard Worker const ENTRIES_PER_PAGE: usize = PAGE_SIZE / std::mem::size_of::<u32>(); 392*bb4ee6a4SAndroid Build Coastguard Worker 393*bb4ee6a4SAndroid Build Coastguard Worker // Fill a vector of the same size as the handle with u32s of increasing value, following 394*bb4ee6a4SAndroid Build Coastguard Worker // the page layout given as argument. 395*bb4ee6a4SAndroid Build Coastguard Worker let mut data = vec![0u8; PAGE_SIZE * page_order.len()]; 396*bb4ee6a4SAndroid Build Coastguard Worker for (page_index, page) in page_order.iter().enumerate() { 397*bb4ee6a4SAndroid Build Coastguard Worker let page_slice = &mut data[(page * PAGE_SIZE)..((page + 1) * PAGE_SIZE)]; 398*bb4ee6a4SAndroid Build Coastguard Worker for (index, chunk) in page_slice.chunks_exact_mut(4).enumerate() { 399*bb4ee6a4SAndroid Build Coastguard Worker let sized_chunk: &mut [u8; 4] = chunk.try_into().unwrap(); 400*bb4ee6a4SAndroid Build Coastguard Worker *sized_chunk = (((page_index * ENTRIES_PER_PAGE) + index) as u32).to_ne_bytes(); 401*bb4ee6a4SAndroid Build Coastguard Worker } 402*bb4ee6a4SAndroid Build Coastguard Worker } 403*bb4ee6a4SAndroid Build Coastguard Worker 404*bb4ee6a4SAndroid Build Coastguard Worker // Copy the initialized vector's content into an anonymous shared memory. 405*bb4ee6a4SAndroid Build Coastguard Worker let mem = SharedMemory::new("data-dest", data.len() as u64).unwrap(); 406*bb4ee6a4SAndroid Build Coastguard Worker let mapping = MemoryMappingBuilder::new(mem.size() as usize) 407*bb4ee6a4SAndroid Build Coastguard Worker .from_shared_memory(&mem) 408*bb4ee6a4SAndroid Build Coastguard Worker .build() 409*bb4ee6a4SAndroid Build Coastguard Worker .unwrap(); 410*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(mapping.write_slice(&data, 0).unwrap(), data.len()); 411*bb4ee6a4SAndroid Build Coastguard Worker 412*bb4ee6a4SAndroid Build Coastguard Worker // Create the `GuestMemHandle` we will try to map and retrieve the data from. 413*bb4ee6a4SAndroid Build Coastguard Worker let mem_handle = GuestResourceHandle::GuestPages(GuestMemHandle { 414*bb4ee6a4SAndroid Build Coastguard Worker desc: base::clone_descriptor(&mem).unwrap(), 415*bb4ee6a4SAndroid Build Coastguard Worker mem_areas: page_order 416*bb4ee6a4SAndroid Build Coastguard Worker .iter() 417*bb4ee6a4SAndroid Build Coastguard Worker .map(|&page| GuestMemArea { 418*bb4ee6a4SAndroid Build Coastguard Worker offset: page as u64 * PAGE_SIZE as u64, 419*bb4ee6a4SAndroid Build Coastguard Worker length: PAGE_SIZE, 420*bb4ee6a4SAndroid Build Coastguard Worker }) 421*bb4ee6a4SAndroid Build Coastguard Worker .collect(), 422*bb4ee6a4SAndroid Build Coastguard Worker }); 423*bb4ee6a4SAndroid Build Coastguard Worker 424*bb4ee6a4SAndroid Build Coastguard Worker // Map the handle into a linear memory area, retrieve its data into a new vector, and check 425*bb4ee6a4SAndroid Build Coastguard Worker // that its u32s appear to increase linearly. 426*bb4ee6a4SAndroid Build Coastguard Worker let mapping = mem_handle.get_mapping(0, mem.size() as usize).unwrap(); 427*bb4ee6a4SAndroid Build Coastguard Worker let mut data = vec![0u8; PAGE_SIZE * page_order.len()]; 428*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: src and dst are valid and aligned 429*bb4ee6a4SAndroid Build Coastguard Worker unsafe { std::ptr::copy_nonoverlapping(mapping.as_ptr(), data.as_mut_ptr(), data.len()) }; 430*bb4ee6a4SAndroid Build Coastguard Worker for (index, chunk) in data.chunks_exact(U32_SIZE).enumerate() { 431*bb4ee6a4SAndroid Build Coastguard Worker let sized_chunk: &[u8; 4] = chunk.try_into().unwrap(); 432*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(u32::from_ne_bytes(*sized_chunk), index as u32); 433*bb4ee6a4SAndroid Build Coastguard Worker } 434*bb4ee6a4SAndroid Build Coastguard Worker } 435*bb4ee6a4SAndroid Build Coastguard Worker 436*bb4ee6a4SAndroid Build Coastguard Worker // Fill a guest memory handle with a single memory page. 437*bb4ee6a4SAndroid Build Coastguard Worker // Then check that the data can be properly mapped and appears in the expected order. 438*bb4ee6a4SAndroid Build Coastguard Worker #[test] test_single_guest_mem_handle()439*bb4ee6a4SAndroid Build Coastguard Worker fn test_single_guest_mem_handle() { 440*bb4ee6a4SAndroid Build Coastguard Worker check_guest_mem_handle(&[0]) 441*bb4ee6a4SAndroid Build Coastguard Worker } 442*bb4ee6a4SAndroid Build Coastguard Worker 443*bb4ee6a4SAndroid Build Coastguard Worker // Fill a guest memory handle with 4 memory pages that are contiguous. 444*bb4ee6a4SAndroid Build Coastguard Worker // Then check that the pages appear in the expected order in the mapping. 445*bb4ee6a4SAndroid Build Coastguard Worker #[test] test_linear_guest_mem_handle()446*bb4ee6a4SAndroid Build Coastguard Worker fn test_linear_guest_mem_handle() { 447*bb4ee6a4SAndroid Build Coastguard Worker check_guest_mem_handle(&[0, 1, 2, 3]) 448*bb4ee6a4SAndroid Build Coastguard Worker } 449*bb4ee6a4SAndroid Build Coastguard Worker 450*bb4ee6a4SAndroid Build Coastguard Worker // Fill a guest memory handle with 8 pages mapped in non-linear order. 451*bb4ee6a4SAndroid Build Coastguard Worker // Then check that the pages appear in the expected order in the mapping. 452*bb4ee6a4SAndroid Build Coastguard Worker #[test] test_sparse_guest_mem_handle()453*bb4ee6a4SAndroid Build Coastguard Worker fn test_sparse_guest_mem_handle() { 454*bb4ee6a4SAndroid Build Coastguard Worker check_guest_mem_handle(&[1, 7, 6, 3, 5, 0, 4, 2]) 455*bb4ee6a4SAndroid Build Coastguard Worker } 456*bb4ee6a4SAndroid Build Coastguard Worker } 457