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::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}