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}
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(&mut self, req: &VhostUserMMap, fd: &dyn AsRawDescriptor) -> HandlerResult<()> {
58 let shared_mapper_state = self
59 .shared_mapper_state
60 .as_mut()
61 .ok_or_else(|| std::io::Error::from_raw_os_error(libc::EINVAL))?;
62 if req.shmid != shared_mapper_state.shmid {
63 error!(
64 "bad shmid {}, expected {}",
65 req.shmid, shared_mapper_state.shmid
66 );
67 return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
68 }
69 shared_mapper_state
70 .mapper
71 .add_mapping(
72 VmMemorySource::Descriptor {
73 descriptor: SafeDescriptor::try_from(fd)
74 .map_err(|_| std::io::Error::from_raw_os_error(libc::EIO))?,
75 offset: req.fd_offset,
76 size: req.len,
77 },
78 req.shm_offset,
79 if req.flags.contains(VhostUserMMapFlags::MAP_RW) {
80 Protection::read_write()
81 } else {
82 Protection::read()
83 },
84 MemCacheType::CacheCoherent,
85 )
86 .map_err(|e| {
87 error!("failed to create mapping {:?}", e);
88 std::io::Error::other(e.context("add descriptor mapping"))
89 })
90 }
91
92 fn shmem_unmap(&mut self, req: &VhostUserMMap) -> HandlerResult<()> {
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 shared_mapper_state
105 .mapper
106 .remove_mapping(req.shm_offset)
107 .map_err(|e| {
108 error!("failed to remove mapping {:?}", e);
109 std::io::Error::other(e.context("remove memory mapping based on shm offset"))
110 })
111 }
112
113 fn gpu_map(
114 &mut self,
115 req: &VhostUserGpuMapMsg,
116 descriptor: &dyn AsRawDescriptor,
117 ) -> HandlerResult<()> {
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 shared_mapper_state
130 .mapper
131 .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 .map_err(|e| {
146 error!("failed to create mapping {:?}", e);
147 std::io::Error::other(e.context("add Vulkan source mapping"))
148 })
149 }
150
151 fn external_map(&mut self, req: &VhostUserExternalMapMsg) -> HandlerResult<()> {
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 shared_mapper_state
164 .mapper
165 .add_mapping(
166 VmMemorySource::ExternalMapping {
167 ptr: req.ptr,
168 size: req.len,
169 },
170 req.shm_offset,
171 Protection::read_write(),
172 MemCacheType::CacheCoherent,
173 )
174 .map_err(|e| {
175 error!("failed to create mapping {:?}", e);
176 std::io::Error::other(e.context("add external mapping"))
177 })
178 }
179
180 fn handle_config_change(&mut self) -> HandlerResult<()> {
181 info!("Handle Config Change called");
182 match &self.interrupt {
183 Some(interrupt) => {
184 interrupt.signal_config_changed();
185 Ok(())
186 }
187 None => {
188 error!("cannot send interrupt");
189 Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
190 }
191 }
192 }
193}