xref: /aosp_15_r20/external/crosvm/vhost/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! Linux vhost kernel API wrapper.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(any(target_os = "android", target_os = "linux"))]
8*bb4ee6a4SAndroid Build Coastguard Worker 
9*bb4ee6a4SAndroid Build Coastguard Worker pub mod net;
10*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
11*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
12*bb4ee6a4SAndroid Build Coastguard Worker mod scmi;
13*bb4ee6a4SAndroid Build Coastguard Worker mod vsock;
14*bb4ee6a4SAndroid Build Coastguard Worker 
15*bb4ee6a4SAndroid Build Coastguard Worker use std::alloc::Layout;
16*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Error as IoError;
17*bb4ee6a4SAndroid Build Coastguard Worker use std::ptr::null;
18*bb4ee6a4SAndroid Build Coastguard Worker 
19*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_mut_ref;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_ptr;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_ref;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
24*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
25*bb4ee6a4SAndroid Build Coastguard Worker use base::LayoutAllocation;
26*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
27*bb4ee6a4SAndroid Build Coastguard Worker use static_assertions::const_assert;
28*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
29*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
30*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
31*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemoryError;
32*bb4ee6a4SAndroid Build Coastguard Worker 
33*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
34*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::net::Net;
35*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
36*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::net::NetT;
37*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_os = "android", target_os = "linux"))]
38*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
39*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::scmi::Scmi;
40*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::vsock::Vsock;
41*bb4ee6a4SAndroid Build Coastguard Worker 
42*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
43*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
44*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
45*bb4ee6a4SAndroid Build Coastguard Worker     /// Invalid available address.
46*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid available address: {0}")]
47*bb4ee6a4SAndroid Build Coastguard Worker     AvailAddress(GuestMemoryError),
48*bb4ee6a4SAndroid Build Coastguard Worker     /// Invalid descriptor table address.
49*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid descriptor table address: {0}")]
50*bb4ee6a4SAndroid Build Coastguard Worker     DescriptorTableAddress(GuestMemoryError),
51*bb4ee6a4SAndroid Build Coastguard Worker     /// Invalid queue.
52*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid queue")]
53*bb4ee6a4SAndroid Build Coastguard Worker     InvalidQueue,
54*bb4ee6a4SAndroid Build Coastguard Worker     /// Error while running ioctl.
55*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to run ioctl: {0}")]
56*bb4ee6a4SAndroid Build Coastguard Worker     IoctlError(IoError),
57*bb4ee6a4SAndroid Build Coastguard Worker     /// Invalid log address.
58*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid log address: {0}")]
59*bb4ee6a4SAndroid Build Coastguard Worker     LogAddress(GuestMemoryError),
60*bb4ee6a4SAndroid Build Coastguard Worker     /// Invalid used address.
61*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid used address: {0}")]
62*bb4ee6a4SAndroid Build Coastguard Worker     UsedAddress(GuestMemoryError),
63*bb4ee6a4SAndroid Build Coastguard Worker     /// Error opening vhost device.
64*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to open vhost device: {0}")]
65*bb4ee6a4SAndroid Build Coastguard Worker     VhostOpen(IoError),
66*bb4ee6a4SAndroid Build Coastguard Worker }
67*bb4ee6a4SAndroid Build Coastguard Worker 
68*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, Error>;
69*bb4ee6a4SAndroid Build Coastguard Worker 
ioctl_result<T>() -> Result<T>70*bb4ee6a4SAndroid Build Coastguard Worker fn ioctl_result<T>() -> Result<T> {
71*bb4ee6a4SAndroid Build Coastguard Worker     Err(Error::IoctlError(IoError::last_os_error()))
72*bb4ee6a4SAndroid Build Coastguard Worker }
73*bb4ee6a4SAndroid Build Coastguard Worker 
74*bb4ee6a4SAndroid Build Coastguard Worker /// An interface for setting up vhost-based virtio devices.  Vhost-based devices are different
75*bb4ee6a4SAndroid Build Coastguard Worker /// from regular virtio devices because the host kernel takes care of handling all the data
76*bb4ee6a4SAndroid Build Coastguard Worker /// transfer.  The device itself only needs to deal with setting up the kernel driver and
77*bb4ee6a4SAndroid Build Coastguard Worker /// managing the control channel.
78*bb4ee6a4SAndroid Build Coastguard Worker pub trait Vhost: AsRawDescriptor + std::marker::Sized {
79*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the current process as the owner of this file descriptor.
80*bb4ee6a4SAndroid Build Coastguard Worker     /// This must be run before any other vhost ioctls.
set_owner(&self) -> Result<()>81*bb4ee6a4SAndroid Build Coastguard Worker     fn set_owner(&self) -> Result<()> {
82*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
83*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net descriptor and has its
84*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
85*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl(self, virtio_sys::VHOST_SET_OWNER) };
86*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
87*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
88*bb4ee6a4SAndroid Build Coastguard Worker         }
89*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
90*bb4ee6a4SAndroid Build Coastguard Worker     }
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker     /// Give up ownership and reset the device to default values. Allows a subsequent call to
93*bb4ee6a4SAndroid Build Coastguard Worker     /// `set_owner` to succeed.
reset_owner(&self) -> Result<()>94*bb4ee6a4SAndroid Build Coastguard Worker     fn reset_owner(&self) -> Result<()> {
95*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
96*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost fd and has its
97*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
98*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl(self, virtio_sys::VHOST_RESET_OWNER) };
99*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
100*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
101*bb4ee6a4SAndroid Build Coastguard Worker         }
102*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
103*bb4ee6a4SAndroid Build Coastguard Worker     }
104*bb4ee6a4SAndroid Build Coastguard Worker 
105*bb4ee6a4SAndroid Build Coastguard Worker     /// Get a bitmask of supported virtio/vhost features.
get_features(&self) -> Result<u64>106*bb4ee6a4SAndroid Build Coastguard Worker     fn get_features(&self) -> Result<u64> {
107*bb4ee6a4SAndroid Build Coastguard Worker         let mut avail_features: u64 = 0;
108*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
109*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net descriptor and has its
110*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
111*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe {
112*bb4ee6a4SAndroid Build Coastguard Worker             ioctl_with_mut_ref(self, virtio_sys::VHOST_GET_FEATURES, &mut avail_features)
113*bb4ee6a4SAndroid Build Coastguard Worker         };
114*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
115*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
116*bb4ee6a4SAndroid Build Coastguard Worker         }
117*bb4ee6a4SAndroid Build Coastguard Worker         Ok(avail_features)
118*bb4ee6a4SAndroid Build Coastguard Worker     }
119*bb4ee6a4SAndroid Build Coastguard Worker 
120*bb4ee6a4SAndroid Build Coastguard Worker     /// Inform the vhost subsystem which features to enable. This should be a subset of
121*bb4ee6a4SAndroid Build Coastguard Worker     /// supported features from VHOST_GET_FEATURES.
122*bb4ee6a4SAndroid Build Coastguard Worker     ///
123*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
124*bb4ee6a4SAndroid Build Coastguard Worker     /// * `features` - Bitmask of features to set.
set_features(&self, features: u64) -> Result<()>125*bb4ee6a4SAndroid Build Coastguard Worker     fn set_features(&self, features: u64) -> Result<()> {
126*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
127*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net descriptor and has its
128*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
129*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_FEATURES, &features) };
130*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
131*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
132*bb4ee6a4SAndroid Build Coastguard Worker         }
133*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
134*bb4ee6a4SAndroid Build Coastguard Worker     }
135*bb4ee6a4SAndroid Build Coastguard Worker 
136*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the guest memory mappings for vhost to use.
set_mem_table(&self, mem: &GuestMemory) -> Result<()>137*bb4ee6a4SAndroid Build Coastguard Worker     fn set_mem_table(&self, mem: &GuestMemory) -> Result<()> {
138*bb4ee6a4SAndroid Build Coastguard Worker         const SIZE_OF_MEMORY: usize = std::mem::size_of::<virtio_sys::vhost::vhost_memory>();
139*bb4ee6a4SAndroid Build Coastguard Worker         const SIZE_OF_REGION: usize = std::mem::size_of::<virtio_sys::vhost::vhost_memory_region>();
140*bb4ee6a4SAndroid Build Coastguard Worker         const ALIGN_OF_MEMORY: usize = std::mem::align_of::<virtio_sys::vhost::vhost_memory>();
141*bb4ee6a4SAndroid Build Coastguard Worker         const_assert!(
142*bb4ee6a4SAndroid Build Coastguard Worker             ALIGN_OF_MEMORY >= std::mem::align_of::<virtio_sys::vhost::vhost_memory_region>()
143*bb4ee6a4SAndroid Build Coastguard Worker         );
144*bb4ee6a4SAndroid Build Coastguard Worker 
145*bb4ee6a4SAndroid Build Coastguard Worker         let num_regions = mem.num_regions() as usize;
146*bb4ee6a4SAndroid Build Coastguard Worker         let size = SIZE_OF_MEMORY + num_regions * SIZE_OF_REGION;
147*bb4ee6a4SAndroid Build Coastguard Worker         let layout = Layout::from_size_align(size, ALIGN_OF_MEMORY).expect("impossible layout");
148*bb4ee6a4SAndroid Build Coastguard Worker         let mut allocation = LayoutAllocation::zeroed(layout);
149*bb4ee6a4SAndroid Build Coastguard Worker 
150*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
151*bb4ee6a4SAndroid Build Coastguard Worker         // Safe to obtain an exclusive reference because there are no other
152*bb4ee6a4SAndroid Build Coastguard Worker         // references to the allocation yet and all-zero is a valid bit pattern.
153*bb4ee6a4SAndroid Build Coastguard Worker         let vhost_memory = unsafe { allocation.as_mut::<virtio_sys::vhost::vhost_memory>() };
154*bb4ee6a4SAndroid Build Coastguard Worker 
155*bb4ee6a4SAndroid Build Coastguard Worker         vhost_memory.nregions = num_regions as u32;
156*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
157*bb4ee6a4SAndroid Build Coastguard Worker         // regions is a zero-length array, so taking a mut slice requires that
158*bb4ee6a4SAndroid Build Coastguard Worker         // we correctly specify the size to match the amount of backing memory.
159*bb4ee6a4SAndroid Build Coastguard Worker         let vhost_regions = unsafe { vhost_memory.regions.as_mut_slice(num_regions) };
160*bb4ee6a4SAndroid Build Coastguard Worker 
161*bb4ee6a4SAndroid Build Coastguard Worker         for region in mem.regions() {
162*bb4ee6a4SAndroid Build Coastguard Worker             vhost_regions[region.index] = virtio_sys::vhost::vhost_memory_region {
163*bb4ee6a4SAndroid Build Coastguard Worker                 guest_phys_addr: region.guest_addr.offset(),
164*bb4ee6a4SAndroid Build Coastguard Worker                 memory_size: region.size as u64,
165*bb4ee6a4SAndroid Build Coastguard Worker                 userspace_addr: region.host_addr as u64,
166*bb4ee6a4SAndroid Build Coastguard Worker                 flags_padding: 0u64,
167*bb4ee6a4SAndroid Build Coastguard Worker             };
168*bb4ee6a4SAndroid Build Coastguard Worker         }
169*bb4ee6a4SAndroid Build Coastguard Worker 
170*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
171*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called with a pointer that is valid for the lifetime
172*bb4ee6a4SAndroid Build Coastguard Worker         // of this function. The kernel will make its own copy of the memory
173*bb4ee6a4SAndroid Build Coastguard Worker         // tables. As always, check the return value.
174*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ptr(self, virtio_sys::VHOST_SET_MEM_TABLE, vhost_memory) };
175*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
176*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
177*bb4ee6a4SAndroid Build Coastguard Worker         }
178*bb4ee6a4SAndroid Build Coastguard Worker 
179*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
180*bb4ee6a4SAndroid Build Coastguard Worker 
181*bb4ee6a4SAndroid Build Coastguard Worker         // vhost_memory allocation is deallocated.
182*bb4ee6a4SAndroid Build Coastguard Worker     }
183*bb4ee6a4SAndroid Build Coastguard Worker 
184*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the number of descriptors in the vring.
185*bb4ee6a4SAndroid Build Coastguard Worker     ///
186*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
187*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_index` - Index of the queue to set descriptor count for.
188*bb4ee6a4SAndroid Build Coastguard Worker     /// * `num` - Number of descriptors in the queue.
set_vring_num(&self, queue_index: usize, num: u16) -> Result<()>189*bb4ee6a4SAndroid Build Coastguard Worker     fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> {
190*bb4ee6a4SAndroid Build Coastguard Worker         let vring_state = virtio_sys::vhost::vhost_vring_state {
191*bb4ee6a4SAndroid Build Coastguard Worker             index: queue_index as u32,
192*bb4ee6a4SAndroid Build Coastguard Worker             num: num as u32,
193*bb4ee6a4SAndroid Build Coastguard Worker         };
194*bb4ee6a4SAndroid Build Coastguard Worker 
195*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
196*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net descriptor and has its
197*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
198*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_NUM, &vring_state) };
199*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
200*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
201*bb4ee6a4SAndroid Build Coastguard Worker         }
202*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
203*bb4ee6a4SAndroid Build Coastguard Worker     }
204*bb4ee6a4SAndroid Build Coastguard Worker 
205*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the addresses for a given vring.
206*bb4ee6a4SAndroid Build Coastguard Worker     ///
207*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
208*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_max_size` - Maximum queue size supported by the device.
209*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_size` - Actual queue size negotiated by the driver.
210*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_index` - Index of the queue to set addresses for.
211*bb4ee6a4SAndroid Build Coastguard Worker     /// * `flags` - Bitmask of vring flags.
212*bb4ee6a4SAndroid Build Coastguard Worker     /// * `desc_addr` - Descriptor table address.
213*bb4ee6a4SAndroid Build Coastguard Worker     /// * `used_addr` - Used ring buffer address.
214*bb4ee6a4SAndroid Build Coastguard Worker     /// * `avail_addr` - Available ring buffer address.
215*bb4ee6a4SAndroid Build Coastguard Worker     /// * `log_addr` - Optional address for logging.
set_vring_addr( &self, mem: &GuestMemory, queue_max_size: u16, queue_size: u16, queue_index: usize, flags: u32, desc_addr: GuestAddress, used_addr: GuestAddress, avail_addr: GuestAddress, log_addr: Option<GuestAddress>, ) -> Result<()>216*bb4ee6a4SAndroid Build Coastguard Worker     fn set_vring_addr(
217*bb4ee6a4SAndroid Build Coastguard Worker         &self,
218*bb4ee6a4SAndroid Build Coastguard Worker         mem: &GuestMemory,
219*bb4ee6a4SAndroid Build Coastguard Worker         queue_max_size: u16,
220*bb4ee6a4SAndroid Build Coastguard Worker         queue_size: u16,
221*bb4ee6a4SAndroid Build Coastguard Worker         queue_index: usize,
222*bb4ee6a4SAndroid Build Coastguard Worker         flags: u32,
223*bb4ee6a4SAndroid Build Coastguard Worker         desc_addr: GuestAddress,
224*bb4ee6a4SAndroid Build Coastguard Worker         used_addr: GuestAddress,
225*bb4ee6a4SAndroid Build Coastguard Worker         avail_addr: GuestAddress,
226*bb4ee6a4SAndroid Build Coastguard Worker         log_addr: Option<GuestAddress>,
227*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
228*bb4ee6a4SAndroid Build Coastguard Worker         if queue_size > queue_max_size || queue_size == 0 || !queue_size.is_power_of_two() {
229*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InvalidQueue);
230*bb4ee6a4SAndroid Build Coastguard Worker         }
231*bb4ee6a4SAndroid Build Coastguard Worker 
232*bb4ee6a4SAndroid Build Coastguard Worker         let queue_size = usize::from(queue_size);
233*bb4ee6a4SAndroid Build Coastguard Worker 
234*bb4ee6a4SAndroid Build Coastguard Worker         let desc_table_size = 16 * queue_size;
235*bb4ee6a4SAndroid Build Coastguard Worker         let desc_table = mem
236*bb4ee6a4SAndroid Build Coastguard Worker             .get_slice_at_addr(desc_addr, desc_table_size)
237*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::DescriptorTableAddress)?;
238*bb4ee6a4SAndroid Build Coastguard Worker 
239*bb4ee6a4SAndroid Build Coastguard Worker         let used_ring_size = 6 + 8 * queue_size;
240*bb4ee6a4SAndroid Build Coastguard Worker         let used_ring = mem
241*bb4ee6a4SAndroid Build Coastguard Worker             .get_slice_at_addr(used_addr, used_ring_size)
242*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::UsedAddress)?;
243*bb4ee6a4SAndroid Build Coastguard Worker 
244*bb4ee6a4SAndroid Build Coastguard Worker         let avail_ring_size = 6 + 2 * queue_size;
245*bb4ee6a4SAndroid Build Coastguard Worker         let avail_ring = mem
246*bb4ee6a4SAndroid Build Coastguard Worker             .get_slice_at_addr(avail_addr, avail_ring_size)
247*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(Error::AvailAddress)?;
248*bb4ee6a4SAndroid Build Coastguard Worker 
249*bb4ee6a4SAndroid Build Coastguard Worker         let log_addr = match log_addr {
250*bb4ee6a4SAndroid Build Coastguard Worker             None => null(),
251*bb4ee6a4SAndroid Build Coastguard Worker             Some(a) => mem.get_host_address(a).map_err(Error::LogAddress)?,
252*bb4ee6a4SAndroid Build Coastguard Worker         };
253*bb4ee6a4SAndroid Build Coastguard Worker 
254*bb4ee6a4SAndroid Build Coastguard Worker         let vring_addr = virtio_sys::vhost::vhost_vring_addr {
255*bb4ee6a4SAndroid Build Coastguard Worker             index: queue_index as u32,
256*bb4ee6a4SAndroid Build Coastguard Worker             flags,
257*bb4ee6a4SAndroid Build Coastguard Worker             desc_user_addr: desc_table.as_ptr() as u64,
258*bb4ee6a4SAndroid Build Coastguard Worker             used_user_addr: used_ring.as_ptr() as u64,
259*bb4ee6a4SAndroid Build Coastguard Worker             avail_user_addr: avail_ring.as_ptr() as u64,
260*bb4ee6a4SAndroid Build Coastguard Worker             log_guest_addr: log_addr as u64,
261*bb4ee6a4SAndroid Build Coastguard Worker         };
262*bb4ee6a4SAndroid Build Coastguard Worker 
263*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
264*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net descriptor and has its
265*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
266*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_ADDR, &vring_addr) };
267*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
268*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
269*bb4ee6a4SAndroid Build Coastguard Worker         }
270*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
271*bb4ee6a4SAndroid Build Coastguard Worker     }
272*bb4ee6a4SAndroid Build Coastguard Worker 
273*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the first index to look for available descriptors.
274*bb4ee6a4SAndroid Build Coastguard Worker     ///
275*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
276*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_index` - Index of the queue to modify.
277*bb4ee6a4SAndroid Build Coastguard Worker     /// * `num` - Index where available descriptors start.
set_vring_base(&self, queue_index: usize, num: u16) -> Result<()>278*bb4ee6a4SAndroid Build Coastguard Worker     fn set_vring_base(&self, queue_index: usize, num: u16) -> Result<()> {
279*bb4ee6a4SAndroid Build Coastguard Worker         let vring_state = virtio_sys::vhost::vhost_vring_state {
280*bb4ee6a4SAndroid Build Coastguard Worker             index: queue_index as u32,
281*bb4ee6a4SAndroid Build Coastguard Worker             num: num as u32,
282*bb4ee6a4SAndroid Build Coastguard Worker         };
283*bb4ee6a4SAndroid Build Coastguard Worker 
284*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
285*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net descriptor and has its
286*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
287*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_BASE, &vring_state) };
288*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
289*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
290*bb4ee6a4SAndroid Build Coastguard Worker         }
291*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
292*bb4ee6a4SAndroid Build Coastguard Worker     }
293*bb4ee6a4SAndroid Build Coastguard Worker 
294*bb4ee6a4SAndroid Build Coastguard Worker     /// Gets the index of the next available descriptor in the queue.
295*bb4ee6a4SAndroid Build Coastguard Worker     ///
296*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
297*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_index` - Index of the queue to query.
get_vring_base(&self, queue_index: usize) -> Result<u16>298*bb4ee6a4SAndroid Build Coastguard Worker     fn get_vring_base(&self, queue_index: usize) -> Result<u16> {
299*bb4ee6a4SAndroid Build Coastguard Worker         let mut vring_state = virtio_sys::vhost::vhost_vring_state {
300*bb4ee6a4SAndroid Build Coastguard Worker             index: queue_index as u32,
301*bb4ee6a4SAndroid Build Coastguard Worker             num: 0,
302*bb4ee6a4SAndroid Build Coastguard Worker         };
303*bb4ee6a4SAndroid Build Coastguard Worker 
304*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
305*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because this will only modify `vring_state` and we check the return value.
306*bb4ee6a4SAndroid Build Coastguard Worker         let ret =
307*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { ioctl_with_mut_ref(self, virtio_sys::VHOST_GET_VRING_BASE, &mut vring_state) };
308*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
309*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
310*bb4ee6a4SAndroid Build Coastguard Worker         }
311*bb4ee6a4SAndroid Build Coastguard Worker 
312*bb4ee6a4SAndroid Build Coastguard Worker         Ok(vring_state.num as u16)
313*bb4ee6a4SAndroid Build Coastguard Worker     }
314*bb4ee6a4SAndroid Build Coastguard Worker 
315*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the event to trigger when buffers have been used by the host.
316*bb4ee6a4SAndroid Build Coastguard Worker     ///
317*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
318*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_index` - Index of the queue to modify.
319*bb4ee6a4SAndroid Build Coastguard Worker     /// * `event` - Event to trigger.
set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()>320*bb4ee6a4SAndroid Build Coastguard Worker     fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> {
321*bb4ee6a4SAndroid Build Coastguard Worker         let vring_file = virtio_sys::vhost::vhost_vring_file {
322*bb4ee6a4SAndroid Build Coastguard Worker             index: queue_index as u32,
323*bb4ee6a4SAndroid Build Coastguard Worker             fd: event.as_raw_descriptor(),
324*bb4ee6a4SAndroid Build Coastguard Worker         };
325*bb4ee6a4SAndroid Build Coastguard Worker 
326*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
327*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net descriptor and has its
328*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
329*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_CALL, &vring_file) };
330*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
331*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
332*bb4ee6a4SAndroid Build Coastguard Worker         }
333*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
334*bb4ee6a4SAndroid Build Coastguard Worker     }
335*bb4ee6a4SAndroid Build Coastguard Worker 
336*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the event to trigger to signal an error.
337*bb4ee6a4SAndroid Build Coastguard Worker     ///
338*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
339*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_index` - Index of the queue to modify.
340*bb4ee6a4SAndroid Build Coastguard Worker     /// * `event` - Event to trigger.
set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()>341*bb4ee6a4SAndroid Build Coastguard Worker     fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()> {
342*bb4ee6a4SAndroid Build Coastguard Worker         let vring_file = virtio_sys::vhost::vhost_vring_file {
343*bb4ee6a4SAndroid Build Coastguard Worker             index: queue_index as u32,
344*bb4ee6a4SAndroid Build Coastguard Worker             fd: event.as_raw_descriptor(),
345*bb4ee6a4SAndroid Build Coastguard Worker         };
346*bb4ee6a4SAndroid Build Coastguard Worker 
347*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
348*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net fd and has its
349*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
350*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_ERR, &vring_file) };
351*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
352*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
353*bb4ee6a4SAndroid Build Coastguard Worker         }
354*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
355*bb4ee6a4SAndroid Build Coastguard Worker     }
356*bb4ee6a4SAndroid Build Coastguard Worker 
357*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the event that will be signaled by the guest when buffers are
358*bb4ee6a4SAndroid Build Coastguard Worker     /// available for the host to process.
359*bb4ee6a4SAndroid Build Coastguard Worker     ///
360*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
361*bb4ee6a4SAndroid Build Coastguard Worker     /// * `queue_index` - Index of the queue to modify.
362*bb4ee6a4SAndroid Build Coastguard Worker     /// * `event` - Event that will be signaled from guest.
set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()>363*bb4ee6a4SAndroid Build Coastguard Worker     fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> {
364*bb4ee6a4SAndroid Build Coastguard Worker         let vring_file = virtio_sys::vhost::vhost_vring_file {
365*bb4ee6a4SAndroid Build Coastguard Worker             index: queue_index as u32,
366*bb4ee6a4SAndroid Build Coastguard Worker             fd: event.as_raw_descriptor(),
367*bb4ee6a4SAndroid Build Coastguard Worker         };
368*bb4ee6a4SAndroid Build Coastguard Worker 
369*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
370*bb4ee6a4SAndroid Build Coastguard Worker         // This ioctl is called on a valid vhost_net descriptor and has its
371*bb4ee6a4SAndroid Build Coastguard Worker         // return value checked.
372*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(self, virtio_sys::VHOST_SET_VRING_KICK, &vring_file) };
373*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
374*bb4ee6a4SAndroid Build Coastguard Worker             return ioctl_result();
375*bb4ee6a4SAndroid Build Coastguard Worker         }
376*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
377*bb4ee6a4SAndroid Build Coastguard Worker     }
378*bb4ee6a4SAndroid Build Coastguard Worker }
379