devices/virtio/vhost_user_frontend/
handler.rs1use base::error;
6use base::info;
7use base::AsRawDescriptor;
8use base::Protection;
9use base::SafeDescriptor;
10use hypervisor::MemCacheType;
11use vm_control::VmMemorySource;
12use vmm_vhost::message::VhostUserExternalMapMsg;
13use vmm_vhost::message::VhostUserGpuMapMsg;
14use vmm_vhost::message::VhostUserMMap;
15use vmm_vhost::message::VhostUserMMapFlags;
16use vmm_vhost::Frontend;
17use vmm_vhost::FrontendServer;
18use vmm_vhost::HandlerResult;
19
20use crate::virtio::Interrupt;
21use crate::virtio::SharedMemoryMapper;
22
23pub(crate) type BackendReqHandler = FrontendServer<BackendReqHandlerImpl>;
24
25struct SharedMapperState {
26 mapper: Box<dyn SharedMemoryMapper>,
27 shmid: u8,
28}
29
30pub struct BackendReqHandlerImpl {
31 interrupt: Option<Interrupt>,
32 shared_mapper_state: Option<SharedMapperState>,
33 is_remote_backend: bool,
34}
35
36impl BackendReqHandlerImpl {
37 pub(crate) fn new(is_remote_backend: bool) -> Self {
38 BackendReqHandlerImpl {
39 interrupt: None,
40 shared_mapper_state: None,
41 is_remote_backend,
42 }
43 }
44
45 pub(crate) fn set_interrupt(&mut self, interrupt: Interrupt) {
46 self.interrupt = Some(interrupt);
47 }
48
49 pub(crate) fn set_shared_mapper_state(
50 &mut self,
51 mapper: Box<dyn SharedMemoryMapper>,
52 shmid: u8,
53 ) {
54 self.shared_mapper_state = Some(SharedMapperState { mapper, shmid });
55 }
56}
57
58impl Frontend for BackendReqHandlerImpl {
59 fn shmem_map(&mut self, req: &VhostUserMMap, fd: &dyn AsRawDescriptor) -> HandlerResult<()> {
60 let shared_mapper_state = self
61 .shared_mapper_state
62 .as_mut()
63 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?;
64 if req.shmid != shared_mapper_state.shmid {
65 error!(
66 "bad shmid {}, expected {}",
67 req.shmid, shared_mapper_state.shmid
68 );
69 return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
70 }
71 shared_mapper_state
72 .mapper
73 .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 if req.flags.contains(VhostUserMMapFlags::MAP_RW) {
82 Protection::read_write()
83 } else {
84 Protection::read()
85 },
86 MemCacheType::CacheCoherent,
87 )
88 .map_err(|e| {
89 error!("failed to create mapping {:?}", e);
90 std::io::Error::other(e.context("add descriptor mapping"))
91 })
92 }
93
94 fn shmem_unmap(&mut self, req: &VhostUserMMap) -> HandlerResult<()> {
95 let shared_mapper_state = self
96 .shared_mapper_state
97 .as_mut()
98 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?;
99 if req.shmid != shared_mapper_state.shmid {
100 error!(
101 "bad shmid {}, expected {}",
102 req.shmid, shared_mapper_state.shmid
103 );
104 return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
105 }
106 shared_mapper_state
107 .mapper
108 .remove_mapping(req.shm_offset)
109 .map_err(|e| {
110 error!("failed to remove mapping {:?}", e);
111 std::io::Error::other(e.context("remove memory mapping based on shm offset"))
112 })
113 }
114
115 fn gpu_map(
116 &mut self,
117 req: &VhostUserGpuMapMsg,
118 descriptor: &dyn AsRawDescriptor,
119 ) -> HandlerResult<()> {
120 let shared_mapper_state = self
121 .shared_mapper_state
122 .as_mut()
123 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?;
124 if req.shmid != shared_mapper_state.shmid {
125 error!(
126 "bad shmid {}, expected {}",
127 req.shmid, shared_mapper_state.shmid
128 );
129 return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
130 }
131 shared_mapper_state
132 .mapper
133 .add_mapping(
134 VmMemorySource::Vulkan {
135 descriptor: SafeDescriptor::try_from(descriptor)
136 .map_err(|_| std::io::Error::from_raw_os_error(libc::EIO))?,
137 handle_type: req.handle_type,
138 memory_idx: req.memory_idx,
139 device_uuid: req.device_uuid,
140 driver_uuid: req.driver_uuid,
141 size: req.len,
142 },
143 req.shm_offset,
144 Protection::read_write(),
145 MemCacheType::CacheCoherent,
146 )
147 .map_err(|e| {
148 error!("failed to create mapping {:?}", e);
149 std::io::Error::other(e.context("add Vulkan source mapping"))
150 })
151 }
152
153 fn external_map(&mut self, req: &VhostUserExternalMapMsg) -> HandlerResult<()> {
154 if self.is_remote_backend {
157 return Err(std::io::Error::from_raw_os_error(libc::EPERM));
158 }
159
160 let shared_mapper_state = self
161 .shared_mapper_state
162 .as_mut()
163 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?;
164 if req.shmid != shared_mapper_state.shmid {
165 error!(
166 "bad shmid {}, expected {}",
167 req.shmid, shared_mapper_state.shmid
168 );
169 return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
170 }
171 shared_mapper_state
172 .mapper
173 .add_mapping(
174 VmMemorySource::ExternalMapping {
175 ptr: req.ptr,
176 size: req.len,
177 },
178 req.shm_offset,
179 Protection::read_write(),
180 MemCacheType::CacheCoherent,
181 )
182 .map_err(|e| {
183 error!("failed to create mapping {:?}", e);
184 std::io::Error::other(e.context("add external mapping"))
185 })
186 }
187
188 fn handle_config_change(&mut self) -> HandlerResult<()> {
189 info!("Handle Config Change called");
190 match &self.interrupt {
191 Some(interrupt) => {
192 interrupt.signal_config_changed();
193 Ok(())
194 }
195 None => {
196 error!("cannot send interrupt");
197 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
198 }
199 }
200 }
201}