1 // Copyright 2021 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use base::error; 6 use base::info; 7 use base::AsRawDescriptor; 8 use base::Protection; 9 use base::SafeDescriptor; 10 use hypervisor::MemCacheType; 11 use vm_control::VmMemorySource; 12 use vmm_vhost::message::VhostUserExternalMapMsg; 13 use vmm_vhost::message::VhostUserGpuMapMsg; 14 use vmm_vhost::message::VhostUserShmemMapMsg; 15 use vmm_vhost::message::VhostUserShmemUnmapMsg; 16 use vmm_vhost::Frontend; 17 use vmm_vhost::FrontendServer; 18 use vmm_vhost::HandlerResult; 19 20 use crate::virtio::Interrupt; 21 use crate::virtio::SharedMemoryMapper; 22 23 pub(crate) type BackendReqHandler = FrontendServer<BackendReqHandlerImpl>; 24 25 struct SharedMapperState { 26 mapper: Box<dyn SharedMemoryMapper>, 27 shmid: u8, 28 } 29 30 pub struct BackendReqHandlerImpl { 31 interrupt: Option<Interrupt>, 32 shared_mapper_state: Option<SharedMapperState>, 33 } 34 35 impl BackendReqHandlerImpl { new() -> Self36 pub(crate) fn new() -> Self { 37 BackendReqHandlerImpl { 38 interrupt: None, 39 shared_mapper_state: None, 40 } 41 } 42 set_interrupt(&mut self, interrupt: Interrupt)43 pub(crate) fn set_interrupt(&mut self, interrupt: Interrupt) { 44 self.interrupt = Some(interrupt); 45 } 46 set_shared_mapper_state( &mut self, mapper: Box<dyn SharedMemoryMapper>, shmid: u8, )47 pub(crate) fn set_shared_mapper_state( 48 &mut self, 49 mapper: Box<dyn SharedMemoryMapper>, 50 shmid: u8, 51 ) { 52 self.shared_mapper_state = Some(SharedMapperState { mapper, shmid }); 53 } 54 } 55 56 impl Frontend for BackendReqHandlerImpl { shmem_map( &mut self, req: &VhostUserShmemMapMsg, fd: &dyn AsRawDescriptor, ) -> HandlerResult<u64>57 fn shmem_map( 58 &mut self, 59 req: &VhostUserShmemMapMsg, 60 fd: &dyn AsRawDescriptor, 61 ) -> HandlerResult<u64> { 62 let shared_mapper_state = self 63 .shared_mapper_state 64 .as_mut() 65 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?; 66 if req.shmid != shared_mapper_state.shmid { 67 error!( 68 "bad shmid {}, expected {}", 69 req.shmid, shared_mapper_state.shmid 70 ); 71 return Err(std::io::Error::from_raw_os_error(libc::EINVAL)); 72 } 73 match shared_mapper_state.mapper.add_mapping( 74 VmMemorySource::Descriptor { 75 descriptor: SafeDescriptor::try_from(fd) 76 .map_err(|_| std::io::Error::from_raw_os_error(libc::EIO))?, 77 offset: req.fd_offset, 78 size: req.len, 79 }, 80 req.shm_offset, 81 Protection::from(req.flags), 82 MemCacheType::CacheCoherent, 83 ) { 84 Ok(()) => Ok(0), 85 Err(e) => { 86 error!("failed to create mapping {:?}", e); 87 Err(std::io::Error::from_raw_os_error(libc::EINVAL)) 88 } 89 } 90 } 91 shmem_unmap(&mut self, req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64>92 fn shmem_unmap(&mut self, req: &VhostUserShmemUnmapMsg) -> HandlerResult<u64> { 93 let shared_mapper_state = self 94 .shared_mapper_state 95 .as_mut() 96 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?; 97 if req.shmid != shared_mapper_state.shmid { 98 error!( 99 "bad shmid {}, expected {}", 100 req.shmid, shared_mapper_state.shmid 101 ); 102 return Err(std::io::Error::from_raw_os_error(libc::EINVAL)); 103 } 104 match shared_mapper_state.mapper.remove_mapping(req.shm_offset) { 105 Ok(()) => Ok(0), 106 Err(e) => { 107 error!("failed to remove mapping {:?}", e); 108 Err(std::io::Error::from_raw_os_error(libc::EINVAL)) 109 } 110 } 111 } 112 gpu_map( &mut self, req: &VhostUserGpuMapMsg, descriptor: &dyn AsRawDescriptor, ) -> HandlerResult<u64>113 fn gpu_map( 114 &mut self, 115 req: &VhostUserGpuMapMsg, 116 descriptor: &dyn AsRawDescriptor, 117 ) -> HandlerResult<u64> { 118 let shared_mapper_state = self 119 .shared_mapper_state 120 .as_mut() 121 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?; 122 if req.shmid != shared_mapper_state.shmid { 123 error!( 124 "bad shmid {}, expected {}", 125 req.shmid, shared_mapper_state.shmid 126 ); 127 return Err(std::io::Error::from_raw_os_error(libc::EINVAL)); 128 } 129 match shared_mapper_state.mapper.add_mapping( 130 VmMemorySource::Vulkan { 131 descriptor: SafeDescriptor::try_from(descriptor) 132 .map_err(|_| std::io::Error::from_raw_os_error(libc::EIO))?, 133 handle_type: req.handle_type, 134 memory_idx: req.memory_idx, 135 device_uuid: req.device_uuid, 136 driver_uuid: req.driver_uuid, 137 size: req.len, 138 }, 139 req.shm_offset, 140 Protection::read_write(), 141 MemCacheType::CacheCoherent, 142 ) { 143 Ok(()) => Ok(0), 144 Err(e) => { 145 error!("failed to create mapping {:?}", e); 146 Err(std::io::Error::from_raw_os_error(libc::EINVAL)) 147 } 148 } 149 } 150 external_map(&mut self, req: &VhostUserExternalMapMsg) -> HandlerResult<u64>151 fn external_map(&mut self, req: &VhostUserExternalMapMsg) -> HandlerResult<u64> { 152 let shared_mapper_state = self 153 .shared_mapper_state 154 .as_mut() 155 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?; 156 if req.shmid != shared_mapper_state.shmid { 157 error!( 158 "bad shmid {}, expected {}", 159 req.shmid, shared_mapper_state.shmid 160 ); 161 return Err(std::io::Error::from_raw_os_error(libc::EINVAL)); 162 } 163 match shared_mapper_state.mapper.add_mapping( 164 VmMemorySource::ExternalMapping { 165 ptr: req.ptr, 166 size: req.len, 167 }, 168 req.shm_offset, 169 Protection::read_write(), 170 MemCacheType::CacheCoherent, 171 ) { 172 Ok(()) => Ok(0), 173 Err(e) => { 174 error!("failed to create mapping {:?}", e); 175 Err(std::io::Error::from_raw_os_error(libc::EINVAL)) 176 } 177 } 178 } 179 handle_config_change(&mut self) -> HandlerResult<u64>180 fn handle_config_change(&mut self) -> HandlerResult<u64> { 181 info!("Handle Config Change called"); 182 match &self.interrupt { 183 Some(interrupt) => { 184 interrupt.signal_config_changed(); 185 Ok(0) 186 } 187 None => { 188 error!("cannot send interrupt"); 189 Err(std::io::Error::from_raw_os_error(libc::ENOSYS)) 190 } 191 } 192 } 193 } 194