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::VhostUserShmemMapMsg;
15use vmm_vhost::message::VhostUserShmemUnmapMsg;
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}
34
35impl BackendReqHandlerImpl {
36 pub(crate) fn new() -> Self {
37 BackendReqHandlerImpl {
38 interrupt: None,
39 shared_mapper_state: None,
40 }
41 }
42
43 pub(crate) fn set_interrupt(&mut self, interrupt: Interrupt) {
44 self.interrupt = Some(interrupt);
45 }
46
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
56impl Frontend for BackendReqHandlerImpl {
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::other(e.context("add descriptor mapping")))
88 }
89 }
90 }
91
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::other(
109 e.context("remove memory mapping based on shm offset"),
110 ))
111 }
112 }
113 }
114
115 fn gpu_map(
116 &mut self,
117 req: &VhostUserGpuMapMsg,
118 descriptor: &dyn AsRawDescriptor,
119 ) -> HandlerResult<u64> {
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 match shared_mapper_state.mapper.add_mapping(
132 VmMemorySource::Vulkan {
133 descriptor: SafeDescriptor::try_from(descriptor)
134 .map_err(|_| std::io::Error::from_raw_os_error(libc::EIO))?,
135 handle_type: req.handle_type,
136 memory_idx: req.memory_idx,
137 device_uuid: req.device_uuid,
138 driver_uuid: req.driver_uuid,
139 size: req.len,
140 },
141 req.shm_offset,
142 Protection::read_write(),
143 MemCacheType::CacheCoherent,
144 ) {
145 Ok(()) => Ok(0),
146 Err(e) => {
147 error!("failed to create mapping {:?}", e);
148 Err(std::io::Error::other(
149 e.context("add Vulkan source mapping"),
150 ))
151 }
152 }
153 }
154
155 fn external_map(&mut self, req: &VhostUserExternalMapMsg) -> HandlerResult<u64> {
156 let shared_mapper_state = self
157 .shared_mapper_state
158 .as_mut()
159 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?;
160 if req.shmid != shared_mapper_state.shmid {
161 error!(
162 "bad shmid {}, expected {}",
163 req.shmid, shared_mapper_state.shmid
164 );
165 return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
166 }
167 match shared_mapper_state.mapper.add_mapping(
168 VmMemorySource::ExternalMapping {
169 ptr: req.ptr,
170 size: req.len,
171 },
172 req.shm_offset,
173 Protection::read_write(),
174 MemCacheType::CacheCoherent,
175 ) {
176 Ok(()) => Ok(0),
177 Err(e) => {
178 error!("failed to create mapping {:?}", e);
179 Err(std::io::Error::other(e.context("add external mapping")))
180 }
181 }
182 }
183
184 fn handle_config_change(&mut self) -> HandlerResult<u64> {
185 info!("Handle Config Change called");
186 match &self.interrupt {
187 Some(interrupt) => {
188 interrupt.signal_config_changed();
189 Ok(0)
190 }
191 None => {
192 error!("cannot send interrupt");
193 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
194 }
195 }
196 }
197}