devices/virtio/vhost_user_frontend/
handler.rs

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
5use 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}