xref: /aosp_15_r20/external/crosvm/devices/src/vfio.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 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 use std::collections::HashMap;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::ffi::CString;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::OpenOptions;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_ulong;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::prelude::FileExt;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
15*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(all(target_os = "android", target_arch = "aarch64"))]
16*bb4ee6a4SAndroid Build Coastguard Worker use std::ptr::addr_of_mut;
17*bb4ee6a4SAndroid Build Coastguard Worker use std::slice;
18*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_mut_ptr;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_mut_ref;
24*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_ptr;
25*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_ref;
26*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_val;
27*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
28*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
29*bb4ee6a4SAndroid Build Coastguard Worker use base::Error;
30*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
31*bb4ee6a4SAndroid Build Coastguard Worker use base::FromRawDescriptor;
32*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
33*bb4ee6a4SAndroid Build Coastguard Worker use base::SafeDescriptor;
34*bb4ee6a4SAndroid Build Coastguard Worker use cfg_if::cfg_if;
35*bb4ee6a4SAndroid Build Coastguard Worker use data_model::vec_with_array_field;
36*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::DeviceKind;
37*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Vm;
38*bb4ee6a4SAndroid Build Coastguard Worker use once_cell::sync::OnceCell;
39*bb4ee6a4SAndroid Build Coastguard Worker use rand::seq::index::sample;
40*bb4ee6a4SAndroid Build Coastguard Worker use rand::thread_rng;
41*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
42*bb4ee6a4SAndroid Build Coastguard Worker use resources::address_allocator::AddressAllocator;
43*bb4ee6a4SAndroid Build Coastguard Worker use resources::AddressRange;
44*bb4ee6a4SAndroid Build Coastguard Worker use resources::Alloc;
45*bb4ee6a4SAndroid Build Coastguard Worker use resources::Error as ResourcesError;
46*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
47*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
48*bb4ee6a4SAndroid Build Coastguard Worker use vfio_sys::vfio::vfio_acpi_dsm;
49*bb4ee6a4SAndroid Build Coastguard Worker use vfio_sys::vfio::VFIO_IRQ_SET_DATA_BOOL;
50*bb4ee6a4SAndroid Build Coastguard Worker use vfio_sys::*;
51*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
52*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
53*bb4ee6a4SAndroid Build Coastguard Worker 
54*bb4ee6a4SAndroid Build Coastguard Worker use crate::IommuDevType;
55*bb4ee6a4SAndroid Build Coastguard Worker 
56*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
57*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
58*bb4ee6a4SAndroid Build Coastguard Worker pub enum VfioError {
59*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to duplicate VfioContainer")]
60*bb4ee6a4SAndroid Build Coastguard Worker     ContainerDupError,
61*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to set container's IOMMU driver type as {0:?}: {1}")]
62*bb4ee6a4SAndroid Build Coastguard Worker     ContainerSetIOMMU(IommuType, Error),
63*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to create KVM vfio device: {0}")]
64*bb4ee6a4SAndroid Build Coastguard Worker     CreateVfioKvmDevice(Error),
65*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to get Group Status: {0}")]
66*bb4ee6a4SAndroid Build Coastguard Worker     GetGroupStatus(Error),
67*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to get vfio device fd: {0}")]
68*bb4ee6a4SAndroid Build Coastguard Worker     GroupGetDeviceFD(Error),
69*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to add vfio group into vfio container: {0}")]
70*bb4ee6a4SAndroid Build Coastguard Worker     GroupSetContainer(Error),
71*bb4ee6a4SAndroid Build Coastguard Worker     #[error("group is inviable")]
72*bb4ee6a4SAndroid Build Coastguard Worker     GroupViable,
73*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid region index: {0}")]
74*bb4ee6a4SAndroid Build Coastguard Worker     InvalidIndex(usize),
75*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid operation")]
76*bb4ee6a4SAndroid Build Coastguard Worker     InvalidOperation,
77*bb4ee6a4SAndroid Build Coastguard Worker     #[error("invalid file path")]
78*bb4ee6a4SAndroid Build Coastguard Worker     InvalidPath,
79*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to add guest memory map into iommu table: {0}")]
80*bb4ee6a4SAndroid Build Coastguard Worker     IommuDmaMap(Error),
81*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to remove guest memory map from iommu table: {0}")]
82*bb4ee6a4SAndroid Build Coastguard Worker     IommuDmaUnmap(Error),
83*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to get IOMMU cap info from host")]
84*bb4ee6a4SAndroid Build Coastguard Worker     IommuGetCapInfo,
85*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to get IOMMU info from host: {0}")]
86*bb4ee6a4SAndroid Build Coastguard Worker     IommuGetInfo(Error),
87*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to attach device to pKVM pvIOMMU: {0}")]
88*bb4ee6a4SAndroid Build Coastguard Worker     KvmPviommuSetConfig(Error),
89*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to set KVM vfio device's attribute: {0}")]
90*bb4ee6a4SAndroid Build Coastguard Worker     KvmSetDeviceAttr(Error),
91*bb4ee6a4SAndroid Build Coastguard Worker     #[error("AddressAllocator is unavailable")]
92*bb4ee6a4SAndroid Build Coastguard Worker     NoRescAlloc,
93*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to open /dev/vfio/vfio container: {0}")]
94*bb4ee6a4SAndroid Build Coastguard Worker     OpenContainer(io::Error),
95*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to open {1} group: {0}")]
96*bb4ee6a4SAndroid Build Coastguard Worker     OpenGroup(io::Error, String),
97*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to read {1} link: {0}")]
98*bb4ee6a4SAndroid Build Coastguard Worker     ReadLink(io::Error, PathBuf),
99*bb4ee6a4SAndroid Build Coastguard Worker     #[error("resources error: {0}")]
100*bb4ee6a4SAndroid Build Coastguard Worker     Resources(ResourcesError),
101*bb4ee6a4SAndroid Build Coastguard Worker     #[error("unknown vfio device type (flags: {0:#x})")]
102*bb4ee6a4SAndroid Build Coastguard Worker     UnknownDeviceType(u32),
103*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to call vfio device's ACPI _DSM: {0}")]
104*bb4ee6a4SAndroid Build Coastguard Worker     VfioAcpiDsm(Error),
105*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to disable vfio deviece's acpi notification: {0}")]
106*bb4ee6a4SAndroid Build Coastguard Worker     VfioAcpiNotificationDisable(Error),
107*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to enable vfio deviece's acpi notification: {0}")]
108*bb4ee6a4SAndroid Build Coastguard Worker     VfioAcpiNotificationEnable(Error),
109*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to test vfio deviece's acpi notification: {0}")]
110*bb4ee6a4SAndroid Build Coastguard Worker     VfioAcpiNotificationTest(Error),
111*bb4ee6a4SAndroid Build Coastguard Worker     #[error(
112*bb4ee6a4SAndroid Build Coastguard Worker         "vfio API version doesn't match with VFIO_API_VERSION defined in vfio_sys/src/vfio.rs"
113*bb4ee6a4SAndroid Build Coastguard Worker     )]
114*bb4ee6a4SAndroid Build Coastguard Worker     VfioApiVersion,
115*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to get vfio device's info or info doesn't match: {0}")]
116*bb4ee6a4SAndroid Build Coastguard Worker     VfioDeviceGetInfo(Error),
117*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to get vfio device's region info: {0}")]
118*bb4ee6a4SAndroid Build Coastguard Worker     VfioDeviceGetRegionInfo(Error),
119*bb4ee6a4SAndroid Build Coastguard Worker     #[error("container doesn't support IOMMU driver type {0:?}")]
120*bb4ee6a4SAndroid Build Coastguard Worker     VfioIommuSupport(IommuType),
121*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to disable vfio deviece's irq: {0}")]
122*bb4ee6a4SAndroid Build Coastguard Worker     VfioIrqDisable(Error),
123*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to enable vfio deviece's irq: {0}")]
124*bb4ee6a4SAndroid Build Coastguard Worker     VfioIrqEnable(Error),
125*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to mask vfio deviece's irq: {0}")]
126*bb4ee6a4SAndroid Build Coastguard Worker     VfioIrqMask(Error),
127*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to unmask vfio deviece's irq: {0}")]
128*bb4ee6a4SAndroid Build Coastguard Worker     VfioIrqUnmask(Error),
129*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to enter vfio deviece's low power state: {0}")]
130*bb4ee6a4SAndroid Build Coastguard Worker     VfioPmLowPowerEnter(Error),
131*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to exit vfio deviece's low power state: {0}")]
132*bb4ee6a4SAndroid Build Coastguard Worker     VfioPmLowPowerExit(Error),
133*bb4ee6a4SAndroid Build Coastguard Worker }
134*bb4ee6a4SAndroid Build Coastguard Worker 
135*bb4ee6a4SAndroid Build Coastguard Worker type Result<T> = std::result::Result<T, VfioError>;
136*bb4ee6a4SAndroid Build Coastguard Worker 
get_error() -> Error137*bb4ee6a4SAndroid Build Coastguard Worker fn get_error() -> Error {
138*bb4ee6a4SAndroid Build Coastguard Worker     Error::last()
139*bb4ee6a4SAndroid Build Coastguard Worker }
140*bb4ee6a4SAndroid Build Coastguard Worker 
141*bb4ee6a4SAndroid Build Coastguard Worker static KVM_VFIO_FILE: OnceCell<SafeDescriptor> = OnceCell::new();
142*bb4ee6a4SAndroid Build Coastguard Worker 
143*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq)]
144*bb4ee6a4SAndroid Build Coastguard Worker pub enum VfioDeviceType {
145*bb4ee6a4SAndroid Build Coastguard Worker     Pci,
146*bb4ee6a4SAndroid Build Coastguard Worker     Platform,
147*bb4ee6a4SAndroid Build Coastguard Worker }
148*bb4ee6a4SAndroid Build Coastguard Worker 
149*bb4ee6a4SAndroid Build Coastguard Worker enum KvmVfioGroupOps {
150*bb4ee6a4SAndroid Build Coastguard Worker     Add,
151*bb4ee6a4SAndroid Build Coastguard Worker     Delete,
152*bb4ee6a4SAndroid Build Coastguard Worker }
153*bb4ee6a4SAndroid Build Coastguard Worker 
154*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
155*bb4ee6a4SAndroid Build Coastguard Worker pub struct KvmVfioPviommu {
156*bb4ee6a4SAndroid Build Coastguard Worker     file: File,
157*bb4ee6a4SAndroid Build Coastguard Worker }
158*bb4ee6a4SAndroid Build Coastguard Worker 
159*bb4ee6a4SAndroid Build Coastguard Worker impl KvmVfioPviommu {
new(vm: &impl Vm) -> Result<Self>160*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(vm: &impl Vm) -> Result<Self> {
161*bb4ee6a4SAndroid Build Coastguard Worker         cfg_if! {
162*bb4ee6a4SAndroid Build Coastguard Worker             if #[cfg(all(target_os = "android", target_arch = "aarch64"))] {
163*bb4ee6a4SAndroid Build Coastguard Worker                 let file = Self::ioctl_kvm_dev_vfio_pviommu_attach(vm)?;
164*bb4ee6a4SAndroid Build Coastguard Worker 
165*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(Self { file })
166*bb4ee6a4SAndroid Build Coastguard Worker             } else {
167*bb4ee6a4SAndroid Build Coastguard Worker                 let _ = vm;
168*bb4ee6a4SAndroid Build Coastguard Worker                 unimplemented!()
169*bb4ee6a4SAndroid Build Coastguard Worker             }
170*bb4ee6a4SAndroid Build Coastguard Worker         }
171*bb4ee6a4SAndroid Build Coastguard Worker     }
172*bb4ee6a4SAndroid Build Coastguard Worker 
attach<T: AsRawDescriptor>(&self, device: &T, sid_idx: u32, vsid: u32) -> Result<()>173*bb4ee6a4SAndroid Build Coastguard Worker     pub fn attach<T: AsRawDescriptor>(&self, device: &T, sid_idx: u32, vsid: u32) -> Result<()> {
174*bb4ee6a4SAndroid Build Coastguard Worker         cfg_if! {
175*bb4ee6a4SAndroid Build Coastguard Worker             if #[cfg(all(target_os = "android", target_arch = "aarch64"))] {
176*bb4ee6a4SAndroid Build Coastguard Worker                 self.ioctl_kvm_pviommu_set_config(device, sid_idx, vsid)
177*bb4ee6a4SAndroid Build Coastguard Worker             } else {
178*bb4ee6a4SAndroid Build Coastguard Worker                 let _ = device;
179*bb4ee6a4SAndroid Build Coastguard Worker                 let _ = sid_idx;
180*bb4ee6a4SAndroid Build Coastguard Worker                 let _ = vsid;
181*bb4ee6a4SAndroid Build Coastguard Worker                 unimplemented!()
182*bb4ee6a4SAndroid Build Coastguard Worker             }
183*bb4ee6a4SAndroid Build Coastguard Worker         }
184*bb4ee6a4SAndroid Build Coastguard Worker     }
185*bb4ee6a4SAndroid Build Coastguard Worker 
id(&self) -> u32186*bb4ee6a4SAndroid Build Coastguard Worker     pub fn id(&self) -> u32 {
187*bb4ee6a4SAndroid Build Coastguard Worker         let fd = self.as_raw_descriptor();
188*bb4ee6a4SAndroid Build Coastguard Worker         // Guests identify pvIOMMUs to the hypervisor using the corresponding VMM FDs.
189*bb4ee6a4SAndroid Build Coastguard Worker         fd.try_into().unwrap()
190*bb4ee6a4SAndroid Build Coastguard Worker     }
191*bb4ee6a4SAndroid Build Coastguard Worker 
get_sid_count<T: AsRawDescriptor>(vm: &impl Vm, device: &T) -> Result<u32>192*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_sid_count<T: AsRawDescriptor>(vm: &impl Vm, device: &T) -> Result<u32> {
193*bb4ee6a4SAndroid Build Coastguard Worker         cfg_if! {
194*bb4ee6a4SAndroid Build Coastguard Worker             if #[cfg(all(target_os = "android", target_arch = "aarch64"))] {
195*bb4ee6a4SAndroid Build Coastguard Worker                 let info = Self::ioctl_kvm_dev_vfio_pviommu_get_info(vm, device)?;
196*bb4ee6a4SAndroid Build Coastguard Worker 
197*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(info.nr_sids)
198*bb4ee6a4SAndroid Build Coastguard Worker             } else {
199*bb4ee6a4SAndroid Build Coastguard Worker                 let _ = vm;
200*bb4ee6a4SAndroid Build Coastguard Worker                 let _ = device;
201*bb4ee6a4SAndroid Build Coastguard Worker                 unimplemented!()
202*bb4ee6a4SAndroid Build Coastguard Worker             }
203*bb4ee6a4SAndroid Build Coastguard Worker         }
204*bb4ee6a4SAndroid Build Coastguard Worker     }
205*bb4ee6a4SAndroid Build Coastguard Worker 
206*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(all(target_os = "android", target_arch = "aarch64"))]
ioctl_kvm_dev_vfio_pviommu_attach(vm: &impl Vm) -> Result<File>207*bb4ee6a4SAndroid Build Coastguard Worker     fn ioctl_kvm_dev_vfio_pviommu_attach(vm: &impl Vm) -> Result<File> {
208*bb4ee6a4SAndroid Build Coastguard Worker         let kvm_vfio_file = KVM_VFIO_FILE
209*bb4ee6a4SAndroid Build Coastguard Worker             .get_or_try_init(|| vm.create_device(DeviceKind::Vfio))
210*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(VfioError::CreateVfioKvmDevice)?;
211*bb4ee6a4SAndroid Build Coastguard Worker 
212*bb4ee6a4SAndroid Build Coastguard Worker         let vfio_dev_attr = kvm_sys::kvm_device_attr {
213*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
214*bb4ee6a4SAndroid Build Coastguard Worker             group: kvm_sys::KVM_DEV_VFIO_PVIOMMU,
215*bb4ee6a4SAndroid Build Coastguard Worker             attr: kvm_sys::KVM_DEV_VFIO_PVIOMMU_ATTACH as u64,
216*bb4ee6a4SAndroid Build Coastguard Worker             addr: 0,
217*bb4ee6a4SAndroid Build Coastguard Worker         };
218*bb4ee6a4SAndroid Build Coastguard Worker 
219*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
220*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of vfio_dev_attr, which is valid.
221*bb4ee6a4SAndroid Build Coastguard Worker         let ret =
222*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { ioctl_with_ref(kvm_vfio_file, kvm_sys::KVM_SET_DEVICE_ATTR, &vfio_dev_attr) };
223*bb4ee6a4SAndroid Build Coastguard Worker 
224*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
225*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::KvmSetDeviceAttr(get_error()))
226*bb4ee6a4SAndroid Build Coastguard Worker         } else {
227*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY: Safe as we verify the return value.
228*bb4ee6a4SAndroid Build Coastguard Worker             Ok(unsafe { File::from_raw_descriptor(ret) })
229*bb4ee6a4SAndroid Build Coastguard Worker         }
230*bb4ee6a4SAndroid Build Coastguard Worker     }
231*bb4ee6a4SAndroid Build Coastguard Worker 
232*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(all(target_os = "android", target_arch = "aarch64"))]
ioctl_kvm_pviommu_set_config<T: AsRawDescriptor>( &self, device: &T, sid_idx: u32, vsid: u32, ) -> Result<()>233*bb4ee6a4SAndroid Build Coastguard Worker     fn ioctl_kvm_pviommu_set_config<T: AsRawDescriptor>(
234*bb4ee6a4SAndroid Build Coastguard Worker         &self,
235*bb4ee6a4SAndroid Build Coastguard Worker         device: &T,
236*bb4ee6a4SAndroid Build Coastguard Worker         sid_idx: u32,
237*bb4ee6a4SAndroid Build Coastguard Worker         vsid: u32,
238*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
239*bb4ee6a4SAndroid Build Coastguard Worker         let config = kvm_sys::kvm_vfio_iommu_config {
240*bb4ee6a4SAndroid Build Coastguard Worker             device_fd: device.as_raw_descriptor(),
241*bb4ee6a4SAndroid Build Coastguard Worker             sid_idx,
242*bb4ee6a4SAndroid Build Coastguard Worker             vsid,
243*bb4ee6a4SAndroid Build Coastguard Worker         };
244*bb4ee6a4SAndroid Build Coastguard Worker 
245*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
246*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of device and config which are valid, and we verify the return
247*bb4ee6a4SAndroid Build Coastguard Worker         // value.
248*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(self, kvm_sys::KVM_PVIOMMU_SET_CONFIG, &config) };
249*bb4ee6a4SAndroid Build Coastguard Worker 
250*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
251*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::KvmPviommuSetConfig(get_error()))
252*bb4ee6a4SAndroid Build Coastguard Worker         } else {
253*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
254*bb4ee6a4SAndroid Build Coastguard Worker         }
255*bb4ee6a4SAndroid Build Coastguard Worker     }
256*bb4ee6a4SAndroid Build Coastguard Worker 
257*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(all(target_os = "android", target_arch = "aarch64"))]
ioctl_kvm_dev_vfio_pviommu_get_info<T: AsRawDescriptor>( vm: &impl Vm, device: &T, ) -> Result<kvm_sys::kvm_vfio_iommu_info>258*bb4ee6a4SAndroid Build Coastguard Worker     fn ioctl_kvm_dev_vfio_pviommu_get_info<T: AsRawDescriptor>(
259*bb4ee6a4SAndroid Build Coastguard Worker         vm: &impl Vm,
260*bb4ee6a4SAndroid Build Coastguard Worker         device: &T,
261*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<kvm_sys::kvm_vfio_iommu_info> {
262*bb4ee6a4SAndroid Build Coastguard Worker         let kvm_vfio_file = KVM_VFIO_FILE
263*bb4ee6a4SAndroid Build Coastguard Worker             .get_or_try_init(|| vm.create_device(DeviceKind::Vfio))
264*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(VfioError::CreateVfioKvmDevice)?;
265*bb4ee6a4SAndroid Build Coastguard Worker 
266*bb4ee6a4SAndroid Build Coastguard Worker         let mut info = kvm_sys::kvm_vfio_iommu_info {
267*bb4ee6a4SAndroid Build Coastguard Worker             device_fd: device.as_raw_descriptor(),
268*bb4ee6a4SAndroid Build Coastguard Worker             nr_sids: 0,
269*bb4ee6a4SAndroid Build Coastguard Worker         };
270*bb4ee6a4SAndroid Build Coastguard Worker 
271*bb4ee6a4SAndroid Build Coastguard Worker         let vfio_dev_attr = kvm_sys::kvm_device_attr {
272*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
273*bb4ee6a4SAndroid Build Coastguard Worker             group: kvm_sys::KVM_DEV_VFIO_PVIOMMU,
274*bb4ee6a4SAndroid Build Coastguard Worker             attr: kvm_sys::KVM_DEV_VFIO_PVIOMMU_GET_INFO as u64,
275*bb4ee6a4SAndroid Build Coastguard Worker             addr: addr_of_mut!(info) as usize as u64,
276*bb4ee6a4SAndroid Build Coastguard Worker         };
277*bb4ee6a4SAndroid Build Coastguard Worker 
278*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
279*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of vfio_dev_attr, which is valid.
280*bb4ee6a4SAndroid Build Coastguard Worker         let ret =
281*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { ioctl_with_ref(kvm_vfio_file, kvm_sys::KVM_SET_DEVICE_ATTR, &vfio_dev_attr) };
282*bb4ee6a4SAndroid Build Coastguard Worker 
283*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
284*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::KvmSetDeviceAttr(get_error()))
285*bb4ee6a4SAndroid Build Coastguard Worker         } else {
286*bb4ee6a4SAndroid Build Coastguard Worker             Ok(info)
287*bb4ee6a4SAndroid Build Coastguard Worker         }
288*bb4ee6a4SAndroid Build Coastguard Worker     }
289*bb4ee6a4SAndroid Build Coastguard Worker }
290*bb4ee6a4SAndroid Build Coastguard Worker 
291*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for KvmVfioPviommu {
as_raw_descriptor(&self) -> RawDescriptor292*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
293*bb4ee6a4SAndroid Build Coastguard Worker         self.file.as_raw_descriptor()
294*bb4ee6a4SAndroid Build Coastguard Worker     }
295*bb4ee6a4SAndroid Build Coastguard Worker }
296*bb4ee6a4SAndroid Build Coastguard Worker 
297*bb4ee6a4SAndroid Build Coastguard Worker #[repr(u32)]
298*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq)]
299*bb4ee6a4SAndroid Build Coastguard Worker pub enum IommuType {
300*bb4ee6a4SAndroid Build Coastguard Worker     Type1V2 = VFIO_TYPE1v2_IOMMU,
301*bb4ee6a4SAndroid Build Coastguard Worker     PkvmPviommu = VFIO_PKVM_PVIOMMU,
302*bb4ee6a4SAndroid Build Coastguard Worker     // ChromeOS specific vfio_iommu_type1 implementation that is optimized for
303*bb4ee6a4SAndroid Build Coastguard Worker     // small, dynamic mappings. For clients which create large, relatively
304*bb4ee6a4SAndroid Build Coastguard Worker     // static mappings, Type1V2 is still preferred.
305*bb4ee6a4SAndroid Build Coastguard Worker     //
306*bb4ee6a4SAndroid Build Coastguard Worker     // See crrev.com/c/3593528 for the implementation.
307*bb4ee6a4SAndroid Build Coastguard Worker     Type1ChromeOS = 100001,
308*bb4ee6a4SAndroid Build Coastguard Worker }
309*bb4ee6a4SAndroid Build Coastguard Worker 
310*bb4ee6a4SAndroid Build Coastguard Worker /// VfioContainer contain multi VfioGroup, and delegate an IOMMU domain table
311*bb4ee6a4SAndroid Build Coastguard Worker pub struct VfioContainer {
312*bb4ee6a4SAndroid Build Coastguard Worker     container: File,
313*bb4ee6a4SAndroid Build Coastguard Worker     groups: HashMap<u32, Arc<Mutex<VfioGroup>>>,
314*bb4ee6a4SAndroid Build Coastguard Worker     iommu_type: Option<IommuType>,
315*bb4ee6a4SAndroid Build Coastguard Worker }
316*bb4ee6a4SAndroid Build Coastguard Worker 
extract_vfio_struct<T>(bytes: &[u8], offset: usize) -> Option<T> where T: FromBytes,317*bb4ee6a4SAndroid Build Coastguard Worker fn extract_vfio_struct<T>(bytes: &[u8], offset: usize) -> Option<T>
318*bb4ee6a4SAndroid Build Coastguard Worker where
319*bb4ee6a4SAndroid Build Coastguard Worker     T: FromBytes,
320*bb4ee6a4SAndroid Build Coastguard Worker {
321*bb4ee6a4SAndroid Build Coastguard Worker     bytes.get(offset..).and_then(T::read_from_prefix)
322*bb4ee6a4SAndroid Build Coastguard Worker }
323*bb4ee6a4SAndroid Build Coastguard Worker 
324*bb4ee6a4SAndroid Build Coastguard Worker const VFIO_API_VERSION: u8 = 0;
325*bb4ee6a4SAndroid Build Coastguard Worker impl VfioContainer {
new() -> Result<Self>326*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new() -> Result<Self> {
327*bb4ee6a4SAndroid Build Coastguard Worker         let container = OpenOptions::new()
328*bb4ee6a4SAndroid Build Coastguard Worker             .read(true)
329*bb4ee6a4SAndroid Build Coastguard Worker             .write(true)
330*bb4ee6a4SAndroid Build Coastguard Worker             .open("/dev/vfio/vfio")
331*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(VfioError::OpenContainer)?;
332*bb4ee6a4SAndroid Build Coastguard Worker 
333*bb4ee6a4SAndroid Build Coastguard Worker         Self::new_from_container(container)
334*bb4ee6a4SAndroid Build Coastguard Worker     }
335*bb4ee6a4SAndroid Build Coastguard Worker 
336*bb4ee6a4SAndroid Build Coastguard Worker     // Construct a VfioContainer from an exist container file.
new_from_container(container: File) -> Result<Self>337*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_from_container(container: File) -> Result<Self> {
338*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
339*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as file is vfio container descriptor and ioctl is defined by kernel.
340*bb4ee6a4SAndroid Build Coastguard Worker         let version = unsafe { ioctl(&container, VFIO_GET_API_VERSION) };
341*bb4ee6a4SAndroid Build Coastguard Worker         if version as u8 != VFIO_API_VERSION {
342*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::VfioApiVersion);
343*bb4ee6a4SAndroid Build Coastguard Worker         }
344*bb4ee6a4SAndroid Build Coastguard Worker 
345*bb4ee6a4SAndroid Build Coastguard Worker         Ok(VfioContainer {
346*bb4ee6a4SAndroid Build Coastguard Worker             container,
347*bb4ee6a4SAndroid Build Coastguard Worker             groups: HashMap::new(),
348*bb4ee6a4SAndroid Build Coastguard Worker             iommu_type: None,
349*bb4ee6a4SAndroid Build Coastguard Worker         })
350*bb4ee6a4SAndroid Build Coastguard Worker     }
351*bb4ee6a4SAndroid Build Coastguard Worker 
is_group_set(&self, group_id: u32) -> bool352*bb4ee6a4SAndroid Build Coastguard Worker     fn is_group_set(&self, group_id: u32) -> bool {
353*bb4ee6a4SAndroid Build Coastguard Worker         self.groups.contains_key(&group_id)
354*bb4ee6a4SAndroid Build Coastguard Worker     }
355*bb4ee6a4SAndroid Build Coastguard Worker 
check_extension(&self, val: IommuType) -> bool356*bb4ee6a4SAndroid Build Coastguard Worker     fn check_extension(&self, val: IommuType) -> bool {
357*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
358*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as file is vfio container and make sure val is valid.
359*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_val(self, VFIO_CHECK_EXTENSION, val as c_ulong) };
360*bb4ee6a4SAndroid Build Coastguard Worker         ret != 0
361*bb4ee6a4SAndroid Build Coastguard Worker     }
362*bb4ee6a4SAndroid Build Coastguard Worker 
set_iommu(&mut self, val: IommuType) -> i32363*bb4ee6a4SAndroid Build Coastguard Worker     fn set_iommu(&mut self, val: IommuType) -> i32 {
364*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
365*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as file is vfio container and make sure val is valid.
366*bb4ee6a4SAndroid Build Coastguard Worker         unsafe { ioctl_with_val(self, VFIO_SET_IOMMU, val as c_ulong) }
367*bb4ee6a4SAndroid Build Coastguard Worker     }
368*bb4ee6a4SAndroid Build Coastguard Worker 
set_iommu_checked(&mut self, val: IommuType) -> Result<()>369*bb4ee6a4SAndroid Build Coastguard Worker     fn set_iommu_checked(&mut self, val: IommuType) -> Result<()> {
370*bb4ee6a4SAndroid Build Coastguard Worker         if !self.check_extension(val) {
371*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioIommuSupport(val))
372*bb4ee6a4SAndroid Build Coastguard Worker         } else if self.set_iommu(val) != 0 {
373*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::ContainerSetIOMMU(val, get_error()))
374*bb4ee6a4SAndroid Build Coastguard Worker         } else {
375*bb4ee6a4SAndroid Build Coastguard Worker             self.iommu_type = Some(val);
376*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
377*bb4ee6a4SAndroid Build Coastguard Worker         }
378*bb4ee6a4SAndroid Build Coastguard Worker     }
379*bb4ee6a4SAndroid Build Coastguard Worker 
380*bb4ee6a4SAndroid Build Coastguard Worker     /// # Safety
381*bb4ee6a4SAndroid Build Coastguard Worker     ///
382*bb4ee6a4SAndroid Build Coastguard Worker     /// The caller is responsible for determining the safety of the VFIO_IOMMU_MAP_DMA ioctl.
vfio_dma_map( &self, iova: u64, size: u64, user_addr: u64, write_en: bool, ) -> Result<()>383*bb4ee6a4SAndroid Build Coastguard Worker     pub unsafe fn vfio_dma_map(
384*bb4ee6a4SAndroid Build Coastguard Worker         &self,
385*bb4ee6a4SAndroid Build Coastguard Worker         iova: u64,
386*bb4ee6a4SAndroid Build Coastguard Worker         size: u64,
387*bb4ee6a4SAndroid Build Coastguard Worker         user_addr: u64,
388*bb4ee6a4SAndroid Build Coastguard Worker         write_en: bool,
389*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
390*bb4ee6a4SAndroid Build Coastguard Worker         match self
391*bb4ee6a4SAndroid Build Coastguard Worker             .iommu_type
392*bb4ee6a4SAndroid Build Coastguard Worker             .expect("vfio_dma_map called before configuring IOMMU")
393*bb4ee6a4SAndroid Build Coastguard Worker         {
394*bb4ee6a4SAndroid Build Coastguard Worker             IommuType::Type1V2 | IommuType::Type1ChromeOS => {
395*bb4ee6a4SAndroid Build Coastguard Worker                 self.vfio_iommu_type1_dma_map(iova, size, user_addr, write_en)
396*bb4ee6a4SAndroid Build Coastguard Worker             }
397*bb4ee6a4SAndroid Build Coastguard Worker             IommuType::PkvmPviommu => Err(VfioError::InvalidOperation),
398*bb4ee6a4SAndroid Build Coastguard Worker         }
399*bb4ee6a4SAndroid Build Coastguard Worker     }
400*bb4ee6a4SAndroid Build Coastguard Worker 
401*bb4ee6a4SAndroid Build Coastguard Worker     /// # Safety
402*bb4ee6a4SAndroid Build Coastguard Worker     ///
403*bb4ee6a4SAndroid Build Coastguard Worker     /// The caller is responsible for determining the safety of the VFIO_IOMMU_MAP_DMA ioctl.
vfio_iommu_type1_dma_map( &self, iova: u64, size: u64, user_addr: u64, write_en: bool, ) -> Result<()>404*bb4ee6a4SAndroid Build Coastguard Worker     unsafe fn vfio_iommu_type1_dma_map(
405*bb4ee6a4SAndroid Build Coastguard Worker         &self,
406*bb4ee6a4SAndroid Build Coastguard Worker         iova: u64,
407*bb4ee6a4SAndroid Build Coastguard Worker         size: u64,
408*bb4ee6a4SAndroid Build Coastguard Worker         user_addr: u64,
409*bb4ee6a4SAndroid Build Coastguard Worker         write_en: bool,
410*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
411*bb4ee6a4SAndroid Build Coastguard Worker         let mut dma_map = vfio_iommu_type1_dma_map {
412*bb4ee6a4SAndroid Build Coastguard Worker             argsz: mem::size_of::<vfio_iommu_type1_dma_map>() as u32,
413*bb4ee6a4SAndroid Build Coastguard Worker             flags: VFIO_DMA_MAP_FLAG_READ,
414*bb4ee6a4SAndroid Build Coastguard Worker             vaddr: user_addr,
415*bb4ee6a4SAndroid Build Coastguard Worker             iova,
416*bb4ee6a4SAndroid Build Coastguard Worker             size,
417*bb4ee6a4SAndroid Build Coastguard Worker         };
418*bb4ee6a4SAndroid Build Coastguard Worker 
419*bb4ee6a4SAndroid Build Coastguard Worker         if write_en {
420*bb4ee6a4SAndroid Build Coastguard Worker             dma_map.flags |= VFIO_DMA_MAP_FLAG_WRITE;
421*bb4ee6a4SAndroid Build Coastguard Worker         }
422*bb4ee6a4SAndroid Build Coastguard Worker 
423*bb4ee6a4SAndroid Build Coastguard Worker         let ret = ioctl_with_ref(self, VFIO_IOMMU_MAP_DMA, &dma_map);
424*bb4ee6a4SAndroid Build Coastguard Worker         if ret != 0 {
425*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::IommuDmaMap(get_error()));
426*bb4ee6a4SAndroid Build Coastguard Worker         }
427*bb4ee6a4SAndroid Build Coastguard Worker 
428*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
429*bb4ee6a4SAndroid Build Coastguard Worker     }
430*bb4ee6a4SAndroid Build Coastguard Worker 
vfio_dma_unmap(&self, iova: u64, size: u64) -> Result<()>431*bb4ee6a4SAndroid Build Coastguard Worker     pub fn vfio_dma_unmap(&self, iova: u64, size: u64) -> Result<()> {
432*bb4ee6a4SAndroid Build Coastguard Worker         match self
433*bb4ee6a4SAndroid Build Coastguard Worker             .iommu_type
434*bb4ee6a4SAndroid Build Coastguard Worker             .expect("vfio_dma_unmap called before configuring IOMMU")
435*bb4ee6a4SAndroid Build Coastguard Worker         {
436*bb4ee6a4SAndroid Build Coastguard Worker             IommuType::Type1V2 | IommuType::Type1ChromeOS => {
437*bb4ee6a4SAndroid Build Coastguard Worker                 self.vfio_iommu_type1_dma_unmap(iova, size)
438*bb4ee6a4SAndroid Build Coastguard Worker             }
439*bb4ee6a4SAndroid Build Coastguard Worker             IommuType::PkvmPviommu => Err(VfioError::InvalidOperation),
440*bb4ee6a4SAndroid Build Coastguard Worker         }
441*bb4ee6a4SAndroid Build Coastguard Worker     }
442*bb4ee6a4SAndroid Build Coastguard Worker 
vfio_iommu_type1_dma_unmap(&self, iova: u64, size: u64) -> Result<()>443*bb4ee6a4SAndroid Build Coastguard Worker     fn vfio_iommu_type1_dma_unmap(&self, iova: u64, size: u64) -> Result<()> {
444*bb4ee6a4SAndroid Build Coastguard Worker         let mut dma_unmap = vfio_iommu_type1_dma_unmap {
445*bb4ee6a4SAndroid Build Coastguard Worker             argsz: mem::size_of::<vfio_iommu_type1_dma_unmap>() as u32,
446*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
447*bb4ee6a4SAndroid Build Coastguard Worker             iova,
448*bb4ee6a4SAndroid Build Coastguard Worker             size,
449*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
450*bb4ee6a4SAndroid Build Coastguard Worker         };
451*bb4ee6a4SAndroid Build Coastguard Worker 
452*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
453*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as file is vfio container, dma_unmap is constructed by us, and
454*bb4ee6a4SAndroid Build Coastguard Worker         // we check the return value
455*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_mut_ref(self, VFIO_IOMMU_UNMAP_DMA, &mut dma_unmap) };
456*bb4ee6a4SAndroid Build Coastguard Worker         if ret != 0 || dma_unmap.size != size {
457*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::IommuDmaUnmap(get_error()));
458*bb4ee6a4SAndroid Build Coastguard Worker         }
459*bb4ee6a4SAndroid Build Coastguard Worker 
460*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
461*bb4ee6a4SAndroid Build Coastguard Worker     }
462*bb4ee6a4SAndroid Build Coastguard Worker 
vfio_get_iommu_page_size_mask(&self) -> Result<u64>463*bb4ee6a4SAndroid Build Coastguard Worker     pub fn vfio_get_iommu_page_size_mask(&self) -> Result<u64> {
464*bb4ee6a4SAndroid Build Coastguard Worker         match self
465*bb4ee6a4SAndroid Build Coastguard Worker             .iommu_type
466*bb4ee6a4SAndroid Build Coastguard Worker             .expect("vfio_get_iommu_page_size_mask called before configuring IOMMU")
467*bb4ee6a4SAndroid Build Coastguard Worker         {
468*bb4ee6a4SAndroid Build Coastguard Worker             IommuType::Type1V2 | IommuType::Type1ChromeOS => {
469*bb4ee6a4SAndroid Build Coastguard Worker                 self.vfio_iommu_type1_get_iommu_page_size_mask()
470*bb4ee6a4SAndroid Build Coastguard Worker             }
471*bb4ee6a4SAndroid Build Coastguard Worker             IommuType::PkvmPviommu => Ok(0),
472*bb4ee6a4SAndroid Build Coastguard Worker         }
473*bb4ee6a4SAndroid Build Coastguard Worker     }
474*bb4ee6a4SAndroid Build Coastguard Worker 
vfio_iommu_type1_get_iommu_page_size_mask(&self) -> Result<u64>475*bb4ee6a4SAndroid Build Coastguard Worker     fn vfio_iommu_type1_get_iommu_page_size_mask(&self) -> Result<u64> {
476*bb4ee6a4SAndroid Build Coastguard Worker         let mut iommu_info = vfio_iommu_type1_info {
477*bb4ee6a4SAndroid Build Coastguard Worker             argsz: mem::size_of::<vfio_iommu_type1_info>() as u32,
478*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
479*bb4ee6a4SAndroid Build Coastguard Worker             iova_pgsizes: 0,
480*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
481*bb4ee6a4SAndroid Build Coastguard Worker         };
482*bb4ee6a4SAndroid Build Coastguard Worker 
483*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
484*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as file is vfio container, iommu_info has valid values,
485*bb4ee6a4SAndroid Build Coastguard Worker         // and we check the return value
486*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_mut_ref(self, VFIO_IOMMU_GET_INFO, &mut iommu_info) };
487*bb4ee6a4SAndroid Build Coastguard Worker         if ret != 0 || (iommu_info.flags & VFIO_IOMMU_INFO_PGSIZES) == 0 {
488*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::IommuGetInfo(get_error()));
489*bb4ee6a4SAndroid Build Coastguard Worker         }
490*bb4ee6a4SAndroid Build Coastguard Worker 
491*bb4ee6a4SAndroid Build Coastguard Worker         Ok(iommu_info.iova_pgsizes)
492*bb4ee6a4SAndroid Build Coastguard Worker     }
493*bb4ee6a4SAndroid Build Coastguard Worker 
vfio_iommu_iova_get_iova_ranges(&self) -> Result<Vec<AddressRange>>494*bb4ee6a4SAndroid Build Coastguard Worker     pub fn vfio_iommu_iova_get_iova_ranges(&self) -> Result<Vec<AddressRange>> {
495*bb4ee6a4SAndroid Build Coastguard Worker         match self
496*bb4ee6a4SAndroid Build Coastguard Worker             .iommu_type
497*bb4ee6a4SAndroid Build Coastguard Worker             .expect("vfio_iommu_iova_get_iova_ranges called before configuring IOMMU")
498*bb4ee6a4SAndroid Build Coastguard Worker         {
499*bb4ee6a4SAndroid Build Coastguard Worker             IommuType::Type1V2 | IommuType::Type1ChromeOS => {
500*bb4ee6a4SAndroid Build Coastguard Worker                 self.vfio_iommu_type1_get_iova_ranges()
501*bb4ee6a4SAndroid Build Coastguard Worker             }
502*bb4ee6a4SAndroid Build Coastguard Worker             IommuType::PkvmPviommu => Ok(Vec::new()),
503*bb4ee6a4SAndroid Build Coastguard Worker         }
504*bb4ee6a4SAndroid Build Coastguard Worker     }
505*bb4ee6a4SAndroid Build Coastguard Worker 
vfio_iommu_type1_get_iova_ranges(&self) -> Result<Vec<AddressRange>>506*bb4ee6a4SAndroid Build Coastguard Worker     fn vfio_iommu_type1_get_iova_ranges(&self) -> Result<Vec<AddressRange>> {
507*bb4ee6a4SAndroid Build Coastguard Worker         // Query the buffer size needed fetch the capabilities.
508*bb4ee6a4SAndroid Build Coastguard Worker         let mut iommu_info_argsz = vfio_iommu_type1_info {
509*bb4ee6a4SAndroid Build Coastguard Worker             argsz: mem::size_of::<vfio_iommu_type1_info>() as u32,
510*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
511*bb4ee6a4SAndroid Build Coastguard Worker             iova_pgsizes: 0,
512*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
513*bb4ee6a4SAndroid Build Coastguard Worker         };
514*bb4ee6a4SAndroid Build Coastguard Worker 
515*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
516*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as file is vfio container, iommu_info_argsz has valid values,
517*bb4ee6a4SAndroid Build Coastguard Worker         // and we check the return value
518*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_mut_ref(self, VFIO_IOMMU_GET_INFO, &mut iommu_info_argsz) };
519*bb4ee6a4SAndroid Build Coastguard Worker         if ret != 0 {
520*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::IommuGetInfo(get_error()));
521*bb4ee6a4SAndroid Build Coastguard Worker         }
522*bb4ee6a4SAndroid Build Coastguard Worker 
523*bb4ee6a4SAndroid Build Coastguard Worker         if (iommu_info_argsz.flags & VFIO_IOMMU_INFO_CAPS) == 0 {
524*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::IommuGetCapInfo);
525*bb4ee6a4SAndroid Build Coastguard Worker         }
526*bb4ee6a4SAndroid Build Coastguard Worker 
527*bb4ee6a4SAndroid Build Coastguard Worker         let mut iommu_info = vec_with_array_field::<vfio_iommu_type1_info, u8>(
528*bb4ee6a4SAndroid Build Coastguard Worker             iommu_info_argsz.argsz as usize - mem::size_of::<vfio_iommu_type1_info>(),
529*bb4ee6a4SAndroid Build Coastguard Worker         );
530*bb4ee6a4SAndroid Build Coastguard Worker         iommu_info[0].argsz = iommu_info_argsz.argsz;
531*bb4ee6a4SAndroid Build Coastguard Worker         let ret =
532*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
533*bb4ee6a4SAndroid Build Coastguard Worker             // Safe as file is vfio container, iommu_info has valid values,
534*bb4ee6a4SAndroid Build Coastguard Worker             // and we check the return value
535*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { ioctl_with_mut_ptr(self, VFIO_IOMMU_GET_INFO, iommu_info.as_mut_ptr()) };
536*bb4ee6a4SAndroid Build Coastguard Worker         if ret != 0 {
537*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::IommuGetInfo(get_error()));
538*bb4ee6a4SAndroid Build Coastguard Worker         }
539*bb4ee6a4SAndroid Build Coastguard Worker 
540*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
541*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we initialized iommu_info with enough space, u8 has less strict
542*bb4ee6a4SAndroid Build Coastguard Worker         // alignment, and since it will no longer be mutated.
543*bb4ee6a4SAndroid Build Coastguard Worker         let info_bytes = unsafe {
544*bb4ee6a4SAndroid Build Coastguard Worker             std::slice::from_raw_parts(
545*bb4ee6a4SAndroid Build Coastguard Worker                 iommu_info.as_ptr() as *const u8,
546*bb4ee6a4SAndroid Build Coastguard Worker                 iommu_info_argsz.argsz as usize,
547*bb4ee6a4SAndroid Build Coastguard Worker             )
548*bb4ee6a4SAndroid Build Coastguard Worker         };
549*bb4ee6a4SAndroid Build Coastguard Worker 
550*bb4ee6a4SAndroid Build Coastguard Worker         if (iommu_info[0].flags & VFIO_IOMMU_INFO_CAPS) == 0 {
551*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::IommuGetCapInfo);
552*bb4ee6a4SAndroid Build Coastguard Worker         }
553*bb4ee6a4SAndroid Build Coastguard Worker 
554*bb4ee6a4SAndroid Build Coastguard Worker         let mut offset = iommu_info[0].cap_offset as usize;
555*bb4ee6a4SAndroid Build Coastguard Worker         while offset != 0 {
556*bb4ee6a4SAndroid Build Coastguard Worker             let header = extract_vfio_struct::<vfio_info_cap_header>(info_bytes, offset)
557*bb4ee6a4SAndroid Build Coastguard Worker                 .ok_or(VfioError::IommuGetCapInfo)?;
558*bb4ee6a4SAndroid Build Coastguard Worker 
559*bb4ee6a4SAndroid Build Coastguard Worker             if header.id == VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE as u16 && header.version == 1 {
560*bb4ee6a4SAndroid Build Coastguard Worker                 let iova_header =
561*bb4ee6a4SAndroid Build Coastguard Worker                     extract_vfio_struct::<vfio_iommu_type1_info_cap_iova_range_header>(
562*bb4ee6a4SAndroid Build Coastguard Worker                         info_bytes, offset,
563*bb4ee6a4SAndroid Build Coastguard Worker                     )
564*bb4ee6a4SAndroid Build Coastguard Worker                     .ok_or(VfioError::IommuGetCapInfo)?;
565*bb4ee6a4SAndroid Build Coastguard Worker                 let range_offset = offset + mem::size_of::<vfio_iommu_type1_info_cap_iova_range>();
566*bb4ee6a4SAndroid Build Coastguard Worker                 let mut ret = Vec::new();
567*bb4ee6a4SAndroid Build Coastguard Worker                 for i in 0..iova_header.nr_iovas {
568*bb4ee6a4SAndroid Build Coastguard Worker                     ret.push(
569*bb4ee6a4SAndroid Build Coastguard Worker                         extract_vfio_struct::<vfio_iova_range>(
570*bb4ee6a4SAndroid Build Coastguard Worker                             info_bytes,
571*bb4ee6a4SAndroid Build Coastguard Worker                             range_offset + i as usize * mem::size_of::<vfio_iova_range>(),
572*bb4ee6a4SAndroid Build Coastguard Worker                         )
573*bb4ee6a4SAndroid Build Coastguard Worker                         .ok_or(VfioError::IommuGetCapInfo)?,
574*bb4ee6a4SAndroid Build Coastguard Worker                     );
575*bb4ee6a4SAndroid Build Coastguard Worker                 }
576*bb4ee6a4SAndroid Build Coastguard Worker                 return Ok(ret
577*bb4ee6a4SAndroid Build Coastguard Worker                     .iter()
578*bb4ee6a4SAndroid Build Coastguard Worker                     .map(|range| AddressRange {
579*bb4ee6a4SAndroid Build Coastguard Worker                         start: range.start,
580*bb4ee6a4SAndroid Build Coastguard Worker                         end: range.end,
581*bb4ee6a4SAndroid Build Coastguard Worker                     })
582*bb4ee6a4SAndroid Build Coastguard Worker                     .collect());
583*bb4ee6a4SAndroid Build Coastguard Worker             }
584*bb4ee6a4SAndroid Build Coastguard Worker             offset = header.next as usize;
585*bb4ee6a4SAndroid Build Coastguard Worker         }
586*bb4ee6a4SAndroid Build Coastguard Worker 
587*bb4ee6a4SAndroid Build Coastguard Worker         Err(VfioError::IommuGetCapInfo)
588*bb4ee6a4SAndroid Build Coastguard Worker     }
589*bb4ee6a4SAndroid Build Coastguard Worker 
set_iommu_from(&mut self, iommu_dev: IommuDevType) -> Result<()>590*bb4ee6a4SAndroid Build Coastguard Worker     fn set_iommu_from(&mut self, iommu_dev: IommuDevType) -> Result<()> {
591*bb4ee6a4SAndroid Build Coastguard Worker         match iommu_dev {
592*bb4ee6a4SAndroid Build Coastguard Worker             IommuDevType::CoIommu | IommuDevType::VirtioIommu => {
593*bb4ee6a4SAndroid Build Coastguard Worker                 // If we expect granular, dynamic mappings, try the ChromeOS Type1ChromeOS first,
594*bb4ee6a4SAndroid Build Coastguard Worker                 // then fall back to upstream versions.
595*bb4ee6a4SAndroid Build Coastguard Worker                 self.set_iommu_checked(IommuType::Type1ChromeOS)
596*bb4ee6a4SAndroid Build Coastguard Worker                     .or_else(|_| self.set_iommu_checked(IommuType::Type1V2))
597*bb4ee6a4SAndroid Build Coastguard Worker             }
598*bb4ee6a4SAndroid Build Coastguard Worker             IommuDevType::NoIommu => self.set_iommu_checked(IommuType::Type1V2),
599*bb4ee6a4SAndroid Build Coastguard Worker             IommuDevType::PkvmPviommu => self.set_iommu_checked(IommuType::PkvmPviommu),
600*bb4ee6a4SAndroid Build Coastguard Worker         }
601*bb4ee6a4SAndroid Build Coastguard Worker     }
602*bb4ee6a4SAndroid Build Coastguard Worker 
get_group_with_vm( &mut self, id: u32, vm: &impl Vm, iommu_dev: IommuDevType, ) -> Result<Arc<Mutex<VfioGroup>>>603*bb4ee6a4SAndroid Build Coastguard Worker     fn get_group_with_vm(
604*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
605*bb4ee6a4SAndroid Build Coastguard Worker         id: u32,
606*bb4ee6a4SAndroid Build Coastguard Worker         vm: &impl Vm,
607*bb4ee6a4SAndroid Build Coastguard Worker         iommu_dev: IommuDevType,
608*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Arc<Mutex<VfioGroup>>> {
609*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(group) = self.groups.get(&id) {
610*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(group.clone());
611*bb4ee6a4SAndroid Build Coastguard Worker         }
612*bb4ee6a4SAndroid Build Coastguard Worker 
613*bb4ee6a4SAndroid Build Coastguard Worker         let group = Arc::new(Mutex::new(VfioGroup::new(self, id)?));
614*bb4ee6a4SAndroid Build Coastguard Worker         if self.groups.is_empty() {
615*bb4ee6a4SAndroid Build Coastguard Worker             self.set_iommu_from(iommu_dev)?;
616*bb4ee6a4SAndroid Build Coastguard Worker             // Before the first group is added into container, do once per container
617*bb4ee6a4SAndroid Build Coastguard Worker             // initialization. Both coiommu and virtio-iommu rely on small, dynamic
618*bb4ee6a4SAndroid Build Coastguard Worker             // mappings. However, if an iommu is not enabled, then we map the entirety
619*bb4ee6a4SAndroid Build Coastguard Worker             // of guest memory as a small number of large, static mappings.
620*bb4ee6a4SAndroid Build Coastguard Worker             match iommu_dev {
621*bb4ee6a4SAndroid Build Coastguard Worker                 IommuDevType::CoIommu | IommuDevType::PkvmPviommu | IommuDevType::VirtioIommu => {}
622*bb4ee6a4SAndroid Build Coastguard Worker                 IommuDevType::NoIommu => {
623*bb4ee6a4SAndroid Build Coastguard Worker                     for region in vm.get_memory().regions() {
624*bb4ee6a4SAndroid Build Coastguard Worker                         // SAFETY:
625*bb4ee6a4SAndroid Build Coastguard Worker                         // Safe because the guest regions are guaranteed not to overlap
626*bb4ee6a4SAndroid Build Coastguard Worker                         unsafe {
627*bb4ee6a4SAndroid Build Coastguard Worker                             self.vfio_dma_map(
628*bb4ee6a4SAndroid Build Coastguard Worker                                 region.guest_addr.0,
629*bb4ee6a4SAndroid Build Coastguard Worker                                 region.size as u64,
630*bb4ee6a4SAndroid Build Coastguard Worker                                 region.host_addr as u64,
631*bb4ee6a4SAndroid Build Coastguard Worker                                 true,
632*bb4ee6a4SAndroid Build Coastguard Worker                             )
633*bb4ee6a4SAndroid Build Coastguard Worker                         }?;
634*bb4ee6a4SAndroid Build Coastguard Worker                     }
635*bb4ee6a4SAndroid Build Coastguard Worker                 }
636*bb4ee6a4SAndroid Build Coastguard Worker             }
637*bb4ee6a4SAndroid Build Coastguard Worker         }
638*bb4ee6a4SAndroid Build Coastguard Worker 
639*bb4ee6a4SAndroid Build Coastguard Worker         let kvm_vfio_file = KVM_VFIO_FILE
640*bb4ee6a4SAndroid Build Coastguard Worker             .get_or_try_init(|| vm.create_device(DeviceKind::Vfio))
641*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(VfioError::CreateVfioKvmDevice)?;
642*bb4ee6a4SAndroid Build Coastguard Worker         group
643*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
644*bb4ee6a4SAndroid Build Coastguard Worker             .kvm_device_set_group(kvm_vfio_file, KvmVfioGroupOps::Add)?;
645*bb4ee6a4SAndroid Build Coastguard Worker 
646*bb4ee6a4SAndroid Build Coastguard Worker         self.groups.insert(id, group.clone());
647*bb4ee6a4SAndroid Build Coastguard Worker 
648*bb4ee6a4SAndroid Build Coastguard Worker         Ok(group)
649*bb4ee6a4SAndroid Build Coastguard Worker     }
650*bb4ee6a4SAndroid Build Coastguard Worker 
get_group(&mut self, id: u32) -> Result<Arc<Mutex<VfioGroup>>>651*bb4ee6a4SAndroid Build Coastguard Worker     fn get_group(&mut self, id: u32) -> Result<Arc<Mutex<VfioGroup>>> {
652*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(group) = self.groups.get(&id) {
653*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(group.clone());
654*bb4ee6a4SAndroid Build Coastguard Worker         }
655*bb4ee6a4SAndroid Build Coastguard Worker 
656*bb4ee6a4SAndroid Build Coastguard Worker         let group = Arc::new(Mutex::new(VfioGroup::new(self, id)?));
657*bb4ee6a4SAndroid Build Coastguard Worker 
658*bb4ee6a4SAndroid Build Coastguard Worker         if self.groups.is_empty() {
659*bb4ee6a4SAndroid Build Coastguard Worker             // Before the first group is added into container, do once per
660*bb4ee6a4SAndroid Build Coastguard Worker             // container initialization.
661*bb4ee6a4SAndroid Build Coastguard Worker             self.set_iommu_checked(IommuType::Type1V2)?;
662*bb4ee6a4SAndroid Build Coastguard Worker         }
663*bb4ee6a4SAndroid Build Coastguard Worker 
664*bb4ee6a4SAndroid Build Coastguard Worker         self.groups.insert(id, group.clone());
665*bb4ee6a4SAndroid Build Coastguard Worker         Ok(group)
666*bb4ee6a4SAndroid Build Coastguard Worker     }
667*bb4ee6a4SAndroid Build Coastguard Worker 
remove_group(&mut self, id: u32, reduce: bool)668*bb4ee6a4SAndroid Build Coastguard Worker     fn remove_group(&mut self, id: u32, reduce: bool) {
669*bb4ee6a4SAndroid Build Coastguard Worker         let mut remove = false;
670*bb4ee6a4SAndroid Build Coastguard Worker 
671*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(group) = self.groups.get(&id) {
672*bb4ee6a4SAndroid Build Coastguard Worker             if reduce {
673*bb4ee6a4SAndroid Build Coastguard Worker                 group.lock().reduce_device_num();
674*bb4ee6a4SAndroid Build Coastguard Worker             }
675*bb4ee6a4SAndroid Build Coastguard Worker             if group.lock().device_num() == 0 {
676*bb4ee6a4SAndroid Build Coastguard Worker                 let kvm_vfio_file = KVM_VFIO_FILE.get().expect("kvm vfio file isn't created");
677*bb4ee6a4SAndroid Build Coastguard Worker                 if group
678*bb4ee6a4SAndroid Build Coastguard Worker                     .lock()
679*bb4ee6a4SAndroid Build Coastguard Worker                     .kvm_device_set_group(kvm_vfio_file, KvmVfioGroupOps::Delete)
680*bb4ee6a4SAndroid Build Coastguard Worker                     .is_err()
681*bb4ee6a4SAndroid Build Coastguard Worker                 {
682*bb4ee6a4SAndroid Build Coastguard Worker                     warn!("failing in remove vfio group from kvm device");
683*bb4ee6a4SAndroid Build Coastguard Worker                 }
684*bb4ee6a4SAndroid Build Coastguard Worker                 remove = true;
685*bb4ee6a4SAndroid Build Coastguard Worker             }
686*bb4ee6a4SAndroid Build Coastguard Worker         }
687*bb4ee6a4SAndroid Build Coastguard Worker 
688*bb4ee6a4SAndroid Build Coastguard Worker         if remove {
689*bb4ee6a4SAndroid Build Coastguard Worker             self.groups.remove(&id);
690*bb4ee6a4SAndroid Build Coastguard Worker         }
691*bb4ee6a4SAndroid Build Coastguard Worker     }
692*bb4ee6a4SAndroid Build Coastguard Worker 
clone_as_raw_descriptor(&self) -> Result<RawDescriptor>693*bb4ee6a4SAndroid Build Coastguard Worker     pub fn clone_as_raw_descriptor(&self) -> Result<RawDescriptor> {
694*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: this call is safe because it doesn't modify any memory and we
695*bb4ee6a4SAndroid Build Coastguard Worker         // check the return value.
696*bb4ee6a4SAndroid Build Coastguard Worker         let raw_descriptor = unsafe { libc::dup(self.container.as_raw_descriptor()) };
697*bb4ee6a4SAndroid Build Coastguard Worker         if raw_descriptor < 0 {
698*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::ContainerDupError)
699*bb4ee6a4SAndroid Build Coastguard Worker         } else {
700*bb4ee6a4SAndroid Build Coastguard Worker             Ok(raw_descriptor)
701*bb4ee6a4SAndroid Build Coastguard Worker         }
702*bb4ee6a4SAndroid Build Coastguard Worker     }
703*bb4ee6a4SAndroid Build Coastguard Worker 
704*bb4ee6a4SAndroid Build Coastguard Worker     // Gets group ids for all groups in the container.
group_ids(&self) -> Vec<&u32>705*bb4ee6a4SAndroid Build Coastguard Worker     pub fn group_ids(&self) -> Vec<&u32> {
706*bb4ee6a4SAndroid Build Coastguard Worker         self.groups.keys().collect()
707*bb4ee6a4SAndroid Build Coastguard Worker     }
708*bb4ee6a4SAndroid Build Coastguard Worker }
709*bb4ee6a4SAndroid Build Coastguard Worker 
710*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for VfioContainer {
as_raw_descriptor(&self) -> RawDescriptor711*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
712*bb4ee6a4SAndroid Build Coastguard Worker         self.container.as_raw_descriptor()
713*bb4ee6a4SAndroid Build Coastguard Worker     }
714*bb4ee6a4SAndroid Build Coastguard Worker }
715*bb4ee6a4SAndroid Build Coastguard Worker 
716*bb4ee6a4SAndroid Build Coastguard Worker struct VfioGroup {
717*bb4ee6a4SAndroid Build Coastguard Worker     group: File,
718*bb4ee6a4SAndroid Build Coastguard Worker     device_num: u32,
719*bb4ee6a4SAndroid Build Coastguard Worker }
720*bb4ee6a4SAndroid Build Coastguard Worker 
721*bb4ee6a4SAndroid Build Coastguard Worker impl VfioGroup {
new(container: &VfioContainer, id: u32) -> Result<Self>722*bb4ee6a4SAndroid Build Coastguard Worker     fn new(container: &VfioContainer, id: u32) -> Result<Self> {
723*bb4ee6a4SAndroid Build Coastguard Worker         let group_path = format!("/dev/vfio/{}", id);
724*bb4ee6a4SAndroid Build Coastguard Worker         let group_file = OpenOptions::new()
725*bb4ee6a4SAndroid Build Coastguard Worker             .read(true)
726*bb4ee6a4SAndroid Build Coastguard Worker             .write(true)
727*bb4ee6a4SAndroid Build Coastguard Worker             .open(Path::new(&group_path))
728*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|e| VfioError::OpenGroup(e, group_path))?;
729*bb4ee6a4SAndroid Build Coastguard Worker 
730*bb4ee6a4SAndroid Build Coastguard Worker         let mut group_status = vfio_group_status {
731*bb4ee6a4SAndroid Build Coastguard Worker             argsz: mem::size_of::<vfio_group_status>() as u32,
732*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
733*bb4ee6a4SAndroid Build Coastguard Worker         };
734*bb4ee6a4SAndroid Build Coastguard Worker         let mut ret =
735*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
736*bb4ee6a4SAndroid Build Coastguard Worker             // Safe as we are the owner of group_file and group_status which are valid value.
737*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { ioctl_with_mut_ref(&group_file, VFIO_GROUP_GET_STATUS, &mut group_status) };
738*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
739*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::GetGroupStatus(get_error()));
740*bb4ee6a4SAndroid Build Coastguard Worker         }
741*bb4ee6a4SAndroid Build Coastguard Worker 
742*bb4ee6a4SAndroid Build Coastguard Worker         if group_status.flags != VFIO_GROUP_FLAGS_VIABLE {
743*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::GroupViable);
744*bb4ee6a4SAndroid Build Coastguard Worker         }
745*bb4ee6a4SAndroid Build Coastguard Worker 
746*bb4ee6a4SAndroid Build Coastguard Worker         let container_raw_descriptor = container.as_raw_descriptor();
747*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
748*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of group_file and container_raw_descriptor which are valid
749*bb4ee6a4SAndroid Build Coastguard Worker         // value, and we verify the ret value
750*bb4ee6a4SAndroid Build Coastguard Worker         ret = unsafe {
751*bb4ee6a4SAndroid Build Coastguard Worker             ioctl_with_ref(
752*bb4ee6a4SAndroid Build Coastguard Worker                 &group_file,
753*bb4ee6a4SAndroid Build Coastguard Worker                 VFIO_GROUP_SET_CONTAINER,
754*bb4ee6a4SAndroid Build Coastguard Worker                 &container_raw_descriptor,
755*bb4ee6a4SAndroid Build Coastguard Worker             )
756*bb4ee6a4SAndroid Build Coastguard Worker         };
757*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
758*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::GroupSetContainer(get_error()));
759*bb4ee6a4SAndroid Build Coastguard Worker         }
760*bb4ee6a4SAndroid Build Coastguard Worker 
761*bb4ee6a4SAndroid Build Coastguard Worker         Ok(VfioGroup {
762*bb4ee6a4SAndroid Build Coastguard Worker             group: group_file,
763*bb4ee6a4SAndroid Build Coastguard Worker             device_num: 0,
764*bb4ee6a4SAndroid Build Coastguard Worker         })
765*bb4ee6a4SAndroid Build Coastguard Worker     }
766*bb4ee6a4SAndroid Build Coastguard Worker 
get_group_id<P: AsRef<Path>>(sysfspath: P) -> Result<u32>767*bb4ee6a4SAndroid Build Coastguard Worker     fn get_group_id<P: AsRef<Path>>(sysfspath: P) -> Result<u32> {
768*bb4ee6a4SAndroid Build Coastguard Worker         let mut uuid_path = PathBuf::new();
769*bb4ee6a4SAndroid Build Coastguard Worker         uuid_path.push(sysfspath);
770*bb4ee6a4SAndroid Build Coastguard Worker         uuid_path.push("iommu_group");
771*bb4ee6a4SAndroid Build Coastguard Worker         let group_path = uuid_path
772*bb4ee6a4SAndroid Build Coastguard Worker             .read_link()
773*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|e| VfioError::ReadLink(e, uuid_path))?;
774*bb4ee6a4SAndroid Build Coastguard Worker         let group_osstr = group_path.file_name().ok_or(VfioError::InvalidPath)?;
775*bb4ee6a4SAndroid Build Coastguard Worker         let group_str = group_osstr.to_str().ok_or(VfioError::InvalidPath)?;
776*bb4ee6a4SAndroid Build Coastguard Worker         let group_id = group_str
777*bb4ee6a4SAndroid Build Coastguard Worker             .parse::<u32>()
778*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(|_| VfioError::InvalidPath)?;
779*bb4ee6a4SAndroid Build Coastguard Worker 
780*bb4ee6a4SAndroid Build Coastguard Worker         Ok(group_id)
781*bb4ee6a4SAndroid Build Coastguard Worker     }
782*bb4ee6a4SAndroid Build Coastguard Worker 
kvm_device_set_group( &self, kvm_vfio_file: &SafeDescriptor, ops: KvmVfioGroupOps, ) -> Result<()>783*bb4ee6a4SAndroid Build Coastguard Worker     fn kvm_device_set_group(
784*bb4ee6a4SAndroid Build Coastguard Worker         &self,
785*bb4ee6a4SAndroid Build Coastguard Worker         kvm_vfio_file: &SafeDescriptor,
786*bb4ee6a4SAndroid Build Coastguard Worker         ops: KvmVfioGroupOps,
787*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
788*bb4ee6a4SAndroid Build Coastguard Worker         let group_descriptor = self.as_raw_descriptor();
789*bb4ee6a4SAndroid Build Coastguard Worker         let group_descriptor_ptr = &group_descriptor as *const i32;
790*bb4ee6a4SAndroid Build Coastguard Worker         let vfio_dev_attr = match ops {
791*bb4ee6a4SAndroid Build Coastguard Worker             KvmVfioGroupOps::Add => kvm_sys::kvm_device_attr {
792*bb4ee6a4SAndroid Build Coastguard Worker                 flags: 0,
793*bb4ee6a4SAndroid Build Coastguard Worker                 group: kvm_sys::KVM_DEV_VFIO_GROUP,
794*bb4ee6a4SAndroid Build Coastguard Worker                 attr: kvm_sys::KVM_DEV_VFIO_GROUP_ADD as u64,
795*bb4ee6a4SAndroid Build Coastguard Worker                 addr: group_descriptor_ptr as u64,
796*bb4ee6a4SAndroid Build Coastguard Worker             },
797*bb4ee6a4SAndroid Build Coastguard Worker             KvmVfioGroupOps::Delete => kvm_sys::kvm_device_attr {
798*bb4ee6a4SAndroid Build Coastguard Worker                 flags: 0,
799*bb4ee6a4SAndroid Build Coastguard Worker                 group: kvm_sys::KVM_DEV_VFIO_GROUP,
800*bb4ee6a4SAndroid Build Coastguard Worker                 attr: kvm_sys::KVM_DEV_VFIO_GROUP_DEL as u64,
801*bb4ee6a4SAndroid Build Coastguard Worker                 addr: group_descriptor_ptr as u64,
802*bb4ee6a4SAndroid Build Coastguard Worker             },
803*bb4ee6a4SAndroid Build Coastguard Worker         };
804*bb4ee6a4SAndroid Build Coastguard Worker 
805*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
806*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of vfio_dev_descriptor and vfio_dev_attr which are valid value,
807*bb4ee6a4SAndroid Build Coastguard Worker         // and we verify the return value.
808*bb4ee6a4SAndroid Build Coastguard Worker         if 0 != unsafe {
809*bb4ee6a4SAndroid Build Coastguard Worker             ioctl_with_ref(kvm_vfio_file, kvm_sys::KVM_SET_DEVICE_ATTR, &vfio_dev_attr)
810*bb4ee6a4SAndroid Build Coastguard Worker         } {
811*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::KvmSetDeviceAttr(get_error()));
812*bb4ee6a4SAndroid Build Coastguard Worker         }
813*bb4ee6a4SAndroid Build Coastguard Worker 
814*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
815*bb4ee6a4SAndroid Build Coastguard Worker     }
816*bb4ee6a4SAndroid Build Coastguard Worker 
get_device(&self, name: &str) -> Result<File>817*bb4ee6a4SAndroid Build Coastguard Worker     fn get_device(&self, name: &str) -> Result<File> {
818*bb4ee6a4SAndroid Build Coastguard Worker         let path: CString = CString::new(name.as_bytes()).expect("CString::new() failed");
819*bb4ee6a4SAndroid Build Coastguard Worker         let path_ptr = path.as_ptr();
820*bb4ee6a4SAndroid Build Coastguard Worker 
821*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
822*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and path_ptr which are valid value.
823*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ptr(self, VFIO_GROUP_GET_DEVICE_FD, path_ptr) };
824*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
825*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::GroupGetDeviceFD(get_error()));
826*bb4ee6a4SAndroid Build Coastguard Worker         }
827*bb4ee6a4SAndroid Build Coastguard Worker 
828*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
829*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as ret is valid descriptor
830*bb4ee6a4SAndroid Build Coastguard Worker         Ok(unsafe { File::from_raw_descriptor(ret) })
831*bb4ee6a4SAndroid Build Coastguard Worker     }
832*bb4ee6a4SAndroid Build Coastguard Worker 
add_device_num(&mut self)833*bb4ee6a4SAndroid Build Coastguard Worker     fn add_device_num(&mut self) {
834*bb4ee6a4SAndroid Build Coastguard Worker         self.device_num += 1;
835*bb4ee6a4SAndroid Build Coastguard Worker     }
836*bb4ee6a4SAndroid Build Coastguard Worker 
reduce_device_num(&mut self)837*bb4ee6a4SAndroid Build Coastguard Worker     fn reduce_device_num(&mut self) {
838*bb4ee6a4SAndroid Build Coastguard Worker         self.device_num -= 1;
839*bb4ee6a4SAndroid Build Coastguard Worker     }
840*bb4ee6a4SAndroid Build Coastguard Worker 
device_num(&self) -> u32841*bb4ee6a4SAndroid Build Coastguard Worker     fn device_num(&self) -> u32 {
842*bb4ee6a4SAndroid Build Coastguard Worker         self.device_num
843*bb4ee6a4SAndroid Build Coastguard Worker     }
844*bb4ee6a4SAndroid Build Coastguard Worker }
845*bb4ee6a4SAndroid Build Coastguard Worker 
846*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for VfioGroup {
as_raw_descriptor(&self) -> RawDescriptor847*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
848*bb4ee6a4SAndroid Build Coastguard Worker         self.group.as_raw_descriptor()
849*bb4ee6a4SAndroid Build Coastguard Worker     }
850*bb4ee6a4SAndroid Build Coastguard Worker }
851*bb4ee6a4SAndroid Build Coastguard Worker 
852*bb4ee6a4SAndroid Build Coastguard Worker /// A helper struct for managing VFIO containers
853*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default)]
854*bb4ee6a4SAndroid Build Coastguard Worker pub struct VfioContainerManager {
855*bb4ee6a4SAndroid Build Coastguard Worker     /// One VFIO container shared by all VFIO devices that don't attach to any IOMMU device.
856*bb4ee6a4SAndroid Build Coastguard Worker     no_iommu_container: Option<Arc<Mutex<VfioContainer>>>,
857*bb4ee6a4SAndroid Build Coastguard Worker 
858*bb4ee6a4SAndroid Build Coastguard Worker     /// For IOMMU enabled devices, all VFIO groups that share the same IOVA space are managed by
859*bb4ee6a4SAndroid Build Coastguard Worker     /// one VFIO container.
860*bb4ee6a4SAndroid Build Coastguard Worker     iommu_containers: Vec<Arc<Mutex<VfioContainer>>>,
861*bb4ee6a4SAndroid Build Coastguard Worker 
862*bb4ee6a4SAndroid Build Coastguard Worker     /// One VFIO container shared by all VFIO devices that attach to the CoIOMMU device.
863*bb4ee6a4SAndroid Build Coastguard Worker     coiommu_container: Option<Arc<Mutex<VfioContainer>>>,
864*bb4ee6a4SAndroid Build Coastguard Worker 
865*bb4ee6a4SAndroid Build Coastguard Worker     /// One VFIO container shared by all VFIO devices that attach to pKVM.
866*bb4ee6a4SAndroid Build Coastguard Worker     pkvm_iommu_container: Option<Arc<Mutex<VfioContainer>>>,
867*bb4ee6a4SAndroid Build Coastguard Worker }
868*bb4ee6a4SAndroid Build Coastguard Worker 
869*bb4ee6a4SAndroid Build Coastguard Worker impl VfioContainerManager {
new() -> Self870*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new() -> Self {
871*bb4ee6a4SAndroid Build Coastguard Worker         Self::default()
872*bb4ee6a4SAndroid Build Coastguard Worker     }
873*bb4ee6a4SAndroid Build Coastguard Worker 
874*bb4ee6a4SAndroid Build Coastguard Worker     /// The single place to create a VFIO container for a PCI endpoint.
875*bb4ee6a4SAndroid Build Coastguard Worker     ///
876*bb4ee6a4SAndroid Build Coastguard Worker     /// The policy to determine whether an individual or a shared VFIO container
877*bb4ee6a4SAndroid Build Coastguard Worker     /// will be created for this device is governed by the physical PCI topology,
878*bb4ee6a4SAndroid Build Coastguard Worker     /// and the argument iommu_type.
879*bb4ee6a4SAndroid Build Coastguard Worker     ///
880*bb4ee6a4SAndroid Build Coastguard Worker     ///  # Arguments
881*bb4ee6a4SAndroid Build Coastguard Worker     ///
882*bb4ee6a4SAndroid Build Coastguard Worker     ///  * `sysfspath` - the path to the PCI device, e.g. /sys/bus/pci/devices/0000:02:00.0
883*bb4ee6a4SAndroid Build Coastguard Worker     ///  * `iommu_type` - which type of IOMMU is enabled on this device
get_container<P: AsRef<Path>>( &mut self, iommu_type: IommuDevType, sysfspath: Option<P>, ) -> Result<Arc<Mutex<VfioContainer>>>884*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_container<P: AsRef<Path>>(
885*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
886*bb4ee6a4SAndroid Build Coastguard Worker         iommu_type: IommuDevType,
887*bb4ee6a4SAndroid Build Coastguard Worker         sysfspath: Option<P>,
888*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Arc<Mutex<VfioContainer>>> {
889*bb4ee6a4SAndroid Build Coastguard Worker         match iommu_type {
890*bb4ee6a4SAndroid Build Coastguard Worker             IommuDevType::NoIommu => {
891*bb4ee6a4SAndroid Build Coastguard Worker                 // One VFIO container is used for all IOMMU disabled groups.
892*bb4ee6a4SAndroid Build Coastguard Worker                 if let Some(container) = &self.no_iommu_container {
893*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(container.clone())
894*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
895*bb4ee6a4SAndroid Build Coastguard Worker                     let container = Arc::new(Mutex::new(VfioContainer::new()?));
896*bb4ee6a4SAndroid Build Coastguard Worker                     self.no_iommu_container = Some(container.clone());
897*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(container)
898*bb4ee6a4SAndroid Build Coastguard Worker                 }
899*bb4ee6a4SAndroid Build Coastguard Worker             }
900*bb4ee6a4SAndroid Build Coastguard Worker             IommuDevType::VirtioIommu => {
901*bb4ee6a4SAndroid Build Coastguard Worker                 let path = sysfspath.ok_or(VfioError::InvalidPath)?;
902*bb4ee6a4SAndroid Build Coastguard Worker                 let group_id = VfioGroup::get_group_id(path)?;
903*bb4ee6a4SAndroid Build Coastguard Worker 
904*bb4ee6a4SAndroid Build Coastguard Worker                 // One VFIO container is used for all devices that belong to one VFIO group.
905*bb4ee6a4SAndroid Build Coastguard Worker                 // NOTE: vfio_wrapper relies on each container containing exactly one group.
906*bb4ee6a4SAndroid Build Coastguard Worker                 if let Some(container) = self
907*bb4ee6a4SAndroid Build Coastguard Worker                     .iommu_containers
908*bb4ee6a4SAndroid Build Coastguard Worker                     .iter()
909*bb4ee6a4SAndroid Build Coastguard Worker                     .find(|container| container.lock().is_group_set(group_id))
910*bb4ee6a4SAndroid Build Coastguard Worker                 {
911*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(container.clone())
912*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
913*bb4ee6a4SAndroid Build Coastguard Worker                     let container = Arc::new(Mutex::new(VfioContainer::new()?));
914*bb4ee6a4SAndroid Build Coastguard Worker                     self.iommu_containers.push(container.clone());
915*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(container)
916*bb4ee6a4SAndroid Build Coastguard Worker                 }
917*bb4ee6a4SAndroid Build Coastguard Worker             }
918*bb4ee6a4SAndroid Build Coastguard Worker             IommuDevType::CoIommu => {
919*bb4ee6a4SAndroid Build Coastguard Worker                 // One VFIO container is used for devices attached to CoIommu
920*bb4ee6a4SAndroid Build Coastguard Worker                 if let Some(container) = &self.coiommu_container {
921*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(container.clone())
922*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
923*bb4ee6a4SAndroid Build Coastguard Worker                     let container = Arc::new(Mutex::new(VfioContainer::new()?));
924*bb4ee6a4SAndroid Build Coastguard Worker                     self.coiommu_container = Some(container.clone());
925*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(container)
926*bb4ee6a4SAndroid Build Coastguard Worker                 }
927*bb4ee6a4SAndroid Build Coastguard Worker             }
928*bb4ee6a4SAndroid Build Coastguard Worker             IommuDevType::PkvmPviommu => {
929*bb4ee6a4SAndroid Build Coastguard Worker                 // One VFIO container is used for devices attached to pKVM
930*bb4ee6a4SAndroid Build Coastguard Worker                 if let Some(container) = &self.pkvm_iommu_container {
931*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(container.clone())
932*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
933*bb4ee6a4SAndroid Build Coastguard Worker                     let container = Arc::new(Mutex::new(VfioContainer::new()?));
934*bb4ee6a4SAndroid Build Coastguard Worker                     self.pkvm_iommu_container = Some(container.clone());
935*bb4ee6a4SAndroid Build Coastguard Worker                     Ok(container)
936*bb4ee6a4SAndroid Build Coastguard Worker                 }
937*bb4ee6a4SAndroid Build Coastguard Worker             }
938*bb4ee6a4SAndroid Build Coastguard Worker         }
939*bb4ee6a4SAndroid Build Coastguard Worker     }
940*bb4ee6a4SAndroid Build Coastguard Worker }
941*bb4ee6a4SAndroid Build Coastguard Worker 
942*bb4ee6a4SAndroid Build Coastguard Worker /// Vfio Irq type used to enable/disable/mask/unmask vfio irq
943*bb4ee6a4SAndroid Build Coastguard Worker pub enum VfioIrqType {
944*bb4ee6a4SAndroid Build Coastguard Worker     Intx,
945*bb4ee6a4SAndroid Build Coastguard Worker     Msi,
946*bb4ee6a4SAndroid Build Coastguard Worker     Msix,
947*bb4ee6a4SAndroid Build Coastguard Worker }
948*bb4ee6a4SAndroid Build Coastguard Worker 
949*bb4ee6a4SAndroid Build Coastguard Worker /// Vfio Irq information used to assign and enable/disable/mask/unmask vfio irq
950*bb4ee6a4SAndroid Build Coastguard Worker pub struct VfioIrq {
951*bb4ee6a4SAndroid Build Coastguard Worker     pub flags: u32,
952*bb4ee6a4SAndroid Build Coastguard Worker     pub index: u32,
953*bb4ee6a4SAndroid Build Coastguard Worker }
954*bb4ee6a4SAndroid Build Coastguard Worker 
955*bb4ee6a4SAndroid Build Coastguard Worker /// Address on VFIO memory region.
956*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Default, Clone)]
957*bb4ee6a4SAndroid Build Coastguard Worker pub struct VfioRegionAddr {
958*bb4ee6a4SAndroid Build Coastguard Worker     /// region number.
959*bb4ee6a4SAndroid Build Coastguard Worker     pub index: usize,
960*bb4ee6a4SAndroid Build Coastguard Worker     /// offset in the region.
961*bb4ee6a4SAndroid Build Coastguard Worker     pub addr: u64,
962*bb4ee6a4SAndroid Build Coastguard Worker }
963*bb4ee6a4SAndroid Build Coastguard Worker 
964*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
965*bb4ee6a4SAndroid Build Coastguard Worker pub struct VfioRegion {
966*bb4ee6a4SAndroid Build Coastguard Worker     // flags for this region: read/write/mmap
967*bb4ee6a4SAndroid Build Coastguard Worker     flags: u32,
968*bb4ee6a4SAndroid Build Coastguard Worker     size: u64,
969*bb4ee6a4SAndroid Build Coastguard Worker     // region offset used to read/write with vfio device descriptor
970*bb4ee6a4SAndroid Build Coastguard Worker     offset: u64,
971*bb4ee6a4SAndroid Build Coastguard Worker     // vectors for mmap offset and size
972*bb4ee6a4SAndroid Build Coastguard Worker     mmaps: Vec<vfio_region_sparse_mmap_area>,
973*bb4ee6a4SAndroid Build Coastguard Worker     // type and subtype for cap type
974*bb4ee6a4SAndroid Build Coastguard Worker     cap_info: Option<(u32, u32)>,
975*bb4ee6a4SAndroid Build Coastguard Worker }
976*bb4ee6a4SAndroid Build Coastguard Worker 
977*bb4ee6a4SAndroid Build Coastguard Worker /// Vfio device for exposing regions which could be read/write to kernel vfio device.
978*bb4ee6a4SAndroid Build Coastguard Worker pub struct VfioDevice {
979*bb4ee6a4SAndroid Build Coastguard Worker     dev: File,
980*bb4ee6a4SAndroid Build Coastguard Worker     name: String,
981*bb4ee6a4SAndroid Build Coastguard Worker     container: Arc<Mutex<VfioContainer>>,
982*bb4ee6a4SAndroid Build Coastguard Worker     dev_type: VfioDeviceType,
983*bb4ee6a4SAndroid Build Coastguard Worker     group_descriptor: RawDescriptor,
984*bb4ee6a4SAndroid Build Coastguard Worker     group_id: u32,
985*bb4ee6a4SAndroid Build Coastguard Worker     // vec for vfio device's regions
986*bb4ee6a4SAndroid Build Coastguard Worker     regions: Vec<VfioRegion>,
987*bb4ee6a4SAndroid Build Coastguard Worker     num_irqs: u32,
988*bb4ee6a4SAndroid Build Coastguard Worker 
989*bb4ee6a4SAndroid Build Coastguard Worker     iova_alloc: Arc<Mutex<AddressAllocator>>,
990*bb4ee6a4SAndroid Build Coastguard Worker     dt_symbol: Option<String>,
991*bb4ee6a4SAndroid Build Coastguard Worker     pviommu: Option<(Arc<Mutex<KvmVfioPviommu>>, Vec<u32>)>,
992*bb4ee6a4SAndroid Build Coastguard Worker }
993*bb4ee6a4SAndroid Build Coastguard Worker 
994*bb4ee6a4SAndroid Build Coastguard Worker impl VfioDevice {
995*bb4ee6a4SAndroid Build Coastguard Worker     /// Create a new vfio device, then guest read/write on this device could be
996*bb4ee6a4SAndroid Build Coastguard Worker     /// transfered into kernel vfio.
997*bb4ee6a4SAndroid Build Coastguard Worker     /// sysfspath specify the vfio device path in sys file system.
new_passthrough<P: AsRef<Path>>( sysfspath: &P, vm: &impl Vm, container: Arc<Mutex<VfioContainer>>, iommu_dev: IommuDevType, dt_symbol: Option<String>, ) -> Result<Self>998*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_passthrough<P: AsRef<Path>>(
999*bb4ee6a4SAndroid Build Coastguard Worker         sysfspath: &P,
1000*bb4ee6a4SAndroid Build Coastguard Worker         vm: &impl Vm,
1001*bb4ee6a4SAndroid Build Coastguard Worker         container: Arc<Mutex<VfioContainer>>,
1002*bb4ee6a4SAndroid Build Coastguard Worker         iommu_dev: IommuDevType,
1003*bb4ee6a4SAndroid Build Coastguard Worker         dt_symbol: Option<String>,
1004*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Self> {
1005*bb4ee6a4SAndroid Build Coastguard Worker         let group_id = VfioGroup::get_group_id(sysfspath)?;
1006*bb4ee6a4SAndroid Build Coastguard Worker 
1007*bb4ee6a4SAndroid Build Coastguard Worker         let group = container
1008*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
1009*bb4ee6a4SAndroid Build Coastguard Worker             .get_group_with_vm(group_id, vm, iommu_dev)?;
1010*bb4ee6a4SAndroid Build Coastguard Worker         let name_osstr = sysfspath
1011*bb4ee6a4SAndroid Build Coastguard Worker             .as_ref()
1012*bb4ee6a4SAndroid Build Coastguard Worker             .file_name()
1013*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(VfioError::InvalidPath)?;
1014*bb4ee6a4SAndroid Build Coastguard Worker         let name_str = name_osstr.to_str().ok_or(VfioError::InvalidPath)?;
1015*bb4ee6a4SAndroid Build Coastguard Worker         let name = String::from(name_str);
1016*bb4ee6a4SAndroid Build Coastguard Worker         let dev = group.lock().get_device(&name)?;
1017*bb4ee6a4SAndroid Build Coastguard Worker         let (dev_info, dev_type) = Self::get_device_info(&dev)?;
1018*bb4ee6a4SAndroid Build Coastguard Worker         let regions = Self::get_regions(&dev, dev_info.num_regions)?;
1019*bb4ee6a4SAndroid Build Coastguard Worker         group.lock().add_device_num();
1020*bb4ee6a4SAndroid Build Coastguard Worker         let group_descriptor = group.lock().as_raw_descriptor();
1021*bb4ee6a4SAndroid Build Coastguard Worker 
1022*bb4ee6a4SAndroid Build Coastguard Worker         let iova_ranges = container.lock().vfio_iommu_iova_get_iova_ranges()?;
1023*bb4ee6a4SAndroid Build Coastguard Worker         let iova_alloc = AddressAllocator::new_from_list(iova_ranges, None, None)
1024*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(VfioError::Resources)?;
1025*bb4ee6a4SAndroid Build Coastguard Worker 
1026*bb4ee6a4SAndroid Build Coastguard Worker         let pviommu = if matches!(iommu_dev, IommuDevType::PkvmPviommu) {
1027*bb4ee6a4SAndroid Build Coastguard Worker             // We currently have a 1-to-1 mapping between pvIOMMUs and VFIO devices.
1028*bb4ee6a4SAndroid Build Coastguard Worker             let pviommu = KvmVfioPviommu::new(vm)?;
1029*bb4ee6a4SAndroid Build Coastguard Worker 
1030*bb4ee6a4SAndroid Build Coastguard Worker             let vsids_len = KvmVfioPviommu::get_sid_count(vm, &dev)?.try_into().unwrap();
1031*bb4ee6a4SAndroid Build Coastguard Worker             let max_vsid = u32::MAX.try_into().unwrap();
1032*bb4ee6a4SAndroid Build Coastguard Worker             let random_vsids = sample(&mut thread_rng(), max_vsid, vsids_len).into_iter();
1033*bb4ee6a4SAndroid Build Coastguard Worker             let vsids = Vec::from_iter(random_vsids.map(|v| u32::try_from(v).unwrap()));
1034*bb4ee6a4SAndroid Build Coastguard Worker             for (i, vsid) in vsids.iter().enumerate() {
1035*bb4ee6a4SAndroid Build Coastguard Worker                 pviommu.attach(&dev, i.try_into().unwrap(), *vsid)?;
1036*bb4ee6a4SAndroid Build Coastguard Worker             }
1037*bb4ee6a4SAndroid Build Coastguard Worker 
1038*bb4ee6a4SAndroid Build Coastguard Worker             Some((Arc::new(Mutex::new(pviommu)), vsids))
1039*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1040*bb4ee6a4SAndroid Build Coastguard Worker             None
1041*bb4ee6a4SAndroid Build Coastguard Worker         };
1042*bb4ee6a4SAndroid Build Coastguard Worker 
1043*bb4ee6a4SAndroid Build Coastguard Worker         Ok(VfioDevice {
1044*bb4ee6a4SAndroid Build Coastguard Worker             dev,
1045*bb4ee6a4SAndroid Build Coastguard Worker             name,
1046*bb4ee6a4SAndroid Build Coastguard Worker             container,
1047*bb4ee6a4SAndroid Build Coastguard Worker             dev_type,
1048*bb4ee6a4SAndroid Build Coastguard Worker             group_descriptor,
1049*bb4ee6a4SAndroid Build Coastguard Worker             group_id,
1050*bb4ee6a4SAndroid Build Coastguard Worker             regions,
1051*bb4ee6a4SAndroid Build Coastguard Worker             num_irqs: dev_info.num_irqs,
1052*bb4ee6a4SAndroid Build Coastguard Worker             iova_alloc: Arc::new(Mutex::new(iova_alloc)),
1053*bb4ee6a4SAndroid Build Coastguard Worker             dt_symbol,
1054*bb4ee6a4SAndroid Build Coastguard Worker             pviommu,
1055*bb4ee6a4SAndroid Build Coastguard Worker         })
1056*bb4ee6a4SAndroid Build Coastguard Worker     }
1057*bb4ee6a4SAndroid Build Coastguard Worker 
new<P: AsRef<Path>>( sysfspath: &P, container: Arc<Mutex<VfioContainer>>, ) -> Result<Self>1058*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new<P: AsRef<Path>>(
1059*bb4ee6a4SAndroid Build Coastguard Worker         sysfspath: &P,
1060*bb4ee6a4SAndroid Build Coastguard Worker         container: Arc<Mutex<VfioContainer>>,
1061*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Self> {
1062*bb4ee6a4SAndroid Build Coastguard Worker         let group_id = VfioGroup::get_group_id(sysfspath)?;
1063*bb4ee6a4SAndroid Build Coastguard Worker         let group = container.lock().get_group(group_id)?;
1064*bb4ee6a4SAndroid Build Coastguard Worker         let name_osstr = sysfspath
1065*bb4ee6a4SAndroid Build Coastguard Worker             .as_ref()
1066*bb4ee6a4SAndroid Build Coastguard Worker             .file_name()
1067*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(VfioError::InvalidPath)?;
1068*bb4ee6a4SAndroid Build Coastguard Worker         let name_str = name_osstr.to_str().ok_or(VfioError::InvalidPath)?;
1069*bb4ee6a4SAndroid Build Coastguard Worker         let name = String::from(name_str);
1070*bb4ee6a4SAndroid Build Coastguard Worker 
1071*bb4ee6a4SAndroid Build Coastguard Worker         let dev = match group.lock().get_device(&name) {
1072*bb4ee6a4SAndroid Build Coastguard Worker             Ok(dev) => dev,
1073*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
1074*bb4ee6a4SAndroid Build Coastguard Worker                 container.lock().remove_group(group_id, false);
1075*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(e);
1076*bb4ee6a4SAndroid Build Coastguard Worker             }
1077*bb4ee6a4SAndroid Build Coastguard Worker         };
1078*bb4ee6a4SAndroid Build Coastguard Worker         let (dev_info, dev_type) = match Self::get_device_info(&dev) {
1079*bb4ee6a4SAndroid Build Coastguard Worker             Ok(dev_info) => dev_info,
1080*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
1081*bb4ee6a4SAndroid Build Coastguard Worker                 container.lock().remove_group(group_id, false);
1082*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(e);
1083*bb4ee6a4SAndroid Build Coastguard Worker             }
1084*bb4ee6a4SAndroid Build Coastguard Worker         };
1085*bb4ee6a4SAndroid Build Coastguard Worker         let regions = match Self::get_regions(&dev, dev_info.num_regions) {
1086*bb4ee6a4SAndroid Build Coastguard Worker             Ok(regions) => regions,
1087*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
1088*bb4ee6a4SAndroid Build Coastguard Worker                 container.lock().remove_group(group_id, false);
1089*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(e);
1090*bb4ee6a4SAndroid Build Coastguard Worker             }
1091*bb4ee6a4SAndroid Build Coastguard Worker         };
1092*bb4ee6a4SAndroid Build Coastguard Worker         group.lock().add_device_num();
1093*bb4ee6a4SAndroid Build Coastguard Worker         let group_descriptor = group.lock().as_raw_descriptor();
1094*bb4ee6a4SAndroid Build Coastguard Worker 
1095*bb4ee6a4SAndroid Build Coastguard Worker         let iova_ranges = container.lock().vfio_iommu_iova_get_iova_ranges()?;
1096*bb4ee6a4SAndroid Build Coastguard Worker         let iova_alloc = AddressAllocator::new_from_list(iova_ranges, None, None)
1097*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(VfioError::Resources)?;
1098*bb4ee6a4SAndroid Build Coastguard Worker 
1099*bb4ee6a4SAndroid Build Coastguard Worker         Ok(VfioDevice {
1100*bb4ee6a4SAndroid Build Coastguard Worker             dev,
1101*bb4ee6a4SAndroid Build Coastguard Worker             name,
1102*bb4ee6a4SAndroid Build Coastguard Worker             container,
1103*bb4ee6a4SAndroid Build Coastguard Worker             dev_type,
1104*bb4ee6a4SAndroid Build Coastguard Worker             group_descriptor,
1105*bb4ee6a4SAndroid Build Coastguard Worker             group_id,
1106*bb4ee6a4SAndroid Build Coastguard Worker             regions,
1107*bb4ee6a4SAndroid Build Coastguard Worker             num_irqs: dev_info.num_irqs,
1108*bb4ee6a4SAndroid Build Coastguard Worker             iova_alloc: Arc::new(Mutex::new(iova_alloc)),
1109*bb4ee6a4SAndroid Build Coastguard Worker             dt_symbol: None,
1110*bb4ee6a4SAndroid Build Coastguard Worker             pviommu: None,
1111*bb4ee6a4SAndroid Build Coastguard Worker         })
1112*bb4ee6a4SAndroid Build Coastguard Worker     }
1113*bb4ee6a4SAndroid Build Coastguard Worker 
1114*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the file for this device.
dev_file(&self) -> &File1115*bb4ee6a4SAndroid Build Coastguard Worker     pub fn dev_file(&self) -> &File {
1116*bb4ee6a4SAndroid Build Coastguard Worker         &self.dev
1117*bb4ee6a4SAndroid Build Coastguard Worker     }
1118*bb4ee6a4SAndroid Build Coastguard Worker 
1119*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns PCI device name, formatted as BUS:DEVICE.FUNCTION string.
device_name(&self) -> &String1120*bb4ee6a4SAndroid Build Coastguard Worker     pub fn device_name(&self) -> &String {
1121*bb4ee6a4SAndroid Build Coastguard Worker         &self.name
1122*bb4ee6a4SAndroid Build Coastguard Worker     }
1123*bb4ee6a4SAndroid Build Coastguard Worker 
1124*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the type of this VFIO device.
device_type(&self) -> VfioDeviceType1125*bb4ee6a4SAndroid Build Coastguard Worker     pub fn device_type(&self) -> VfioDeviceType {
1126*bb4ee6a4SAndroid Build Coastguard Worker         self.dev_type
1127*bb4ee6a4SAndroid Build Coastguard Worker     }
1128*bb4ee6a4SAndroid Build Coastguard Worker 
1129*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the DT symbol (node label) of this VFIO device.
dt_symbol(&self) -> Option<&str>1130*bb4ee6a4SAndroid Build Coastguard Worker     pub fn dt_symbol(&self) -> Option<&str> {
1131*bb4ee6a4SAndroid Build Coastguard Worker         self.dt_symbol.as_deref()
1132*bb4ee6a4SAndroid Build Coastguard Worker     }
1133*bb4ee6a4SAndroid Build Coastguard Worker 
1134*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the type and indentifier (if applicable) of the IOMMU used by this VFIO device and
1135*bb4ee6a4SAndroid Build Coastguard Worker     /// its master IDs.
iommu(&self) -> Option<(IommuDevType, Option<u32>, &[u32])>1136*bb4ee6a4SAndroid Build Coastguard Worker     pub fn iommu(&self) -> Option<(IommuDevType, Option<u32>, &[u32])> {
1137*bb4ee6a4SAndroid Build Coastguard Worker         // We currently only report IommuDevType::PkvmPviommu.
1138*bb4ee6a4SAndroid Build Coastguard Worker         if let Some((ref pviommu, ref ids)) = self.pviommu {
1139*bb4ee6a4SAndroid Build Coastguard Worker             Some((
1140*bb4ee6a4SAndroid Build Coastguard Worker                 IommuDevType::PkvmPviommu,
1141*bb4ee6a4SAndroid Build Coastguard Worker                 Some(pviommu.lock().id()),
1142*bb4ee6a4SAndroid Build Coastguard Worker                 ids.as_ref(),
1143*bb4ee6a4SAndroid Build Coastguard Worker             ))
1144*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1145*bb4ee6a4SAndroid Build Coastguard Worker             None
1146*bb4ee6a4SAndroid Build Coastguard Worker         }
1147*bb4ee6a4SAndroid Build Coastguard Worker     }
1148*bb4ee6a4SAndroid Build Coastguard Worker 
1149*bb4ee6a4SAndroid Build Coastguard Worker     /// enter the device's low power state
pm_low_power_enter(&self) -> Result<()>1150*bb4ee6a4SAndroid Build Coastguard Worker     pub fn pm_low_power_enter(&self) -> Result<()> {
1151*bb4ee6a4SAndroid Build Coastguard Worker         let mut device_feature = vec_with_array_field::<vfio_device_feature, u8>(0);
1152*bb4ee6a4SAndroid Build Coastguard Worker         device_feature[0].argsz = mem::size_of::<vfio_device_feature>() as u32;
1153*bb4ee6a4SAndroid Build Coastguard Worker         device_feature[0].flags = VFIO_DEVICE_FEATURE_SET | VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY;
1154*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1155*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and power_management which are valid value
1156*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_FEATURE, &device_feature[0]) };
1157*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1158*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioPmLowPowerEnter(get_error()))
1159*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1160*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1161*bb4ee6a4SAndroid Build Coastguard Worker         }
1162*bb4ee6a4SAndroid Build Coastguard Worker     }
1163*bb4ee6a4SAndroid Build Coastguard Worker 
1164*bb4ee6a4SAndroid Build Coastguard Worker     /// enter the device's low power state with wakeup notification
pm_low_power_enter_with_wakeup(&self, wakeup_evt: Event) -> Result<()>1165*bb4ee6a4SAndroid Build Coastguard Worker     pub fn pm_low_power_enter_with_wakeup(&self, wakeup_evt: Event) -> Result<()> {
1166*bb4ee6a4SAndroid Build Coastguard Worker         let payload = vfio_device_low_power_entry_with_wakeup {
1167*bb4ee6a4SAndroid Build Coastguard Worker             wakeup_eventfd: wakeup_evt.as_raw_descriptor(),
1168*bb4ee6a4SAndroid Build Coastguard Worker             reserved: 0,
1169*bb4ee6a4SAndroid Build Coastguard Worker         };
1170*bb4ee6a4SAndroid Build Coastguard Worker         let payload_size = mem::size_of::<vfio_device_low_power_entry_with_wakeup>();
1171*bb4ee6a4SAndroid Build Coastguard Worker         let mut device_feature = vec_with_array_field::<vfio_device_feature, u8>(payload_size);
1172*bb4ee6a4SAndroid Build Coastguard Worker         device_feature[0].argsz = (mem::size_of::<vfio_device_feature>() + payload_size) as u32;
1173*bb4ee6a4SAndroid Build Coastguard Worker         device_feature[0].flags =
1174*bb4ee6a4SAndroid Build Coastguard Worker             VFIO_DEVICE_FEATURE_SET | VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY_WITH_WAKEUP;
1175*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1176*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we know vfio_device_low_power_entry_with_wakeup has two 32-bit int fields
1177*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
1178*bb4ee6a4SAndroid Build Coastguard Worker             device_feature[0]
1179*bb4ee6a4SAndroid Build Coastguard Worker                 .data
1180*bb4ee6a4SAndroid Build Coastguard Worker                 .as_mut_slice(payload_size)
1181*bb4ee6a4SAndroid Build Coastguard Worker                 .copy_from_slice(
1182*bb4ee6a4SAndroid Build Coastguard Worker                     mem::transmute::<vfio_device_low_power_entry_with_wakeup, [u8; 8]>(payload)
1183*bb4ee6a4SAndroid Build Coastguard Worker                         .as_slice(),
1184*bb4ee6a4SAndroid Build Coastguard Worker                 );
1185*bb4ee6a4SAndroid Build Coastguard Worker         }
1186*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1187*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and power_management which are valid value
1188*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_FEATURE, &device_feature[0]) };
1189*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1190*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioPmLowPowerEnter(get_error()))
1191*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1192*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1193*bb4ee6a4SAndroid Build Coastguard Worker         }
1194*bb4ee6a4SAndroid Build Coastguard Worker     }
1195*bb4ee6a4SAndroid Build Coastguard Worker 
1196*bb4ee6a4SAndroid Build Coastguard Worker     /// exit the device's low power state
pm_low_power_exit(&self) -> Result<()>1197*bb4ee6a4SAndroid Build Coastguard Worker     pub fn pm_low_power_exit(&self) -> Result<()> {
1198*bb4ee6a4SAndroid Build Coastguard Worker         let mut device_feature = vec_with_array_field::<vfio_device_feature, u8>(0);
1199*bb4ee6a4SAndroid Build Coastguard Worker         device_feature[0].argsz = mem::size_of::<vfio_device_feature>() as u32;
1200*bb4ee6a4SAndroid Build Coastguard Worker         device_feature[0].flags = VFIO_DEVICE_FEATURE_SET | VFIO_DEVICE_FEATURE_LOW_POWER_EXIT;
1201*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1202*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and power_management which are valid value
1203*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_FEATURE, &device_feature[0]) };
1204*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1205*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioPmLowPowerExit(get_error()))
1206*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1207*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1208*bb4ee6a4SAndroid Build Coastguard Worker         }
1209*bb4ee6a4SAndroid Build Coastguard Worker     }
1210*bb4ee6a4SAndroid Build Coastguard Worker 
1211*bb4ee6a4SAndroid Build Coastguard Worker     /// call _DSM from the device's ACPI table
acpi_dsm(&self, args: &[u8]) -> Result<Vec<u8>>1212*bb4ee6a4SAndroid Build Coastguard Worker     pub fn acpi_dsm(&self, args: &[u8]) -> Result<Vec<u8>> {
1213*bb4ee6a4SAndroid Build Coastguard Worker         let count = args.len();
1214*bb4ee6a4SAndroid Build Coastguard Worker         let mut dsm = vec_with_array_field::<vfio_acpi_dsm, u8>(count);
1215*bb4ee6a4SAndroid Build Coastguard Worker         dsm[0].argsz = (mem::size_of::<vfio_acpi_dsm>() + mem::size_of_val(args)) as u32;
1216*bb4ee6a4SAndroid Build Coastguard Worker         dsm[0].padding = 0;
1217*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1218*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we allocated enough space to hold args
1219*bb4ee6a4SAndroid Build Coastguard Worker         unsafe {
1220*bb4ee6a4SAndroid Build Coastguard Worker             dsm[0].args.as_mut_slice(count).clone_from_slice(args);
1221*bb4ee6a4SAndroid Build Coastguard Worker         }
1222*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1223*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and dsm which are valid value
1224*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_mut_ref(&self.dev, VFIO_DEVICE_ACPI_DSM, &mut dsm[0]) };
1225*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1226*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioAcpiDsm(get_error()))
1227*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1228*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
1229*bb4ee6a4SAndroid Build Coastguard Worker             // Safe as we allocated enough space to hold args
1230*bb4ee6a4SAndroid Build Coastguard Worker             let res = unsafe { dsm[0].args.as_slice(count) };
1231*bb4ee6a4SAndroid Build Coastguard Worker             Ok(res.to_vec())
1232*bb4ee6a4SAndroid Build Coastguard Worker         }
1233*bb4ee6a4SAndroid Build Coastguard Worker     }
1234*bb4ee6a4SAndroid Build Coastguard Worker 
1235*bb4ee6a4SAndroid Build Coastguard Worker     /// Enable vfio device's ACPI notifications and associate EventFD with device.
acpi_notification_evt_enable( &self, acpi_notification_eventfd: &Event, index: u32, ) -> Result<()>1236*bb4ee6a4SAndroid Build Coastguard Worker     pub fn acpi_notification_evt_enable(
1237*bb4ee6a4SAndroid Build Coastguard Worker         &self,
1238*bb4ee6a4SAndroid Build Coastguard Worker         acpi_notification_eventfd: &Event,
1239*bb4ee6a4SAndroid Build Coastguard Worker         index: u32,
1240*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
1241*bb4ee6a4SAndroid Build Coastguard Worker         let u32_size = mem::size_of::<u32>();
1242*bb4ee6a4SAndroid Build Coastguard Worker         let count = 1;
1243*bb4ee6a4SAndroid Build Coastguard Worker 
1244*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(count);
1245*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].argsz = (mem::size_of::<vfio_irq_set>() + count * u32_size) as u32;
1246*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
1247*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].index = index;
1248*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].start = 0;
1249*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].count = count as u32;
1250*bb4ee6a4SAndroid Build Coastguard Worker 
1251*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1252*bb4ee6a4SAndroid Build Coastguard Worker         // It is safe as enough space is reserved through vec_with_array_field(u32)<count>.
1253*bb4ee6a4SAndroid Build Coastguard Worker         let data = unsafe { irq_set[0].data.as_mut_slice(count * u32_size) };
1254*bb4ee6a4SAndroid Build Coastguard Worker         data.copy_from_slice(&acpi_notification_eventfd.as_raw_descriptor().to_ne_bytes()[..]);
1255*bb4ee6a4SAndroid Build Coastguard Worker 
1256*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1257*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and irq_set which are valid value
1258*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS, &irq_set[0]) };
1259*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1260*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioAcpiNotificationEnable(get_error()))
1261*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1262*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1263*bb4ee6a4SAndroid Build Coastguard Worker         }
1264*bb4ee6a4SAndroid Build Coastguard Worker     }
1265*bb4ee6a4SAndroid Build Coastguard Worker 
1266*bb4ee6a4SAndroid Build Coastguard Worker     /// Disable vfio device's ACPI notification and disconnect EventFd with device.
acpi_notification_disable(&self, index: u32) -> Result<()>1267*bb4ee6a4SAndroid Build Coastguard Worker     pub fn acpi_notification_disable(&self, index: u32) -> Result<()> {
1268*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(0);
1269*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].argsz = mem::size_of::<vfio_irq_set>() as u32;
1270*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
1271*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].index = index;
1272*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].start = 0;
1273*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].count = 0;
1274*bb4ee6a4SAndroid Build Coastguard Worker 
1275*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1276*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and irq_set which are valid value
1277*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS, &irq_set[0]) };
1278*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1279*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioAcpiNotificationDisable(get_error()))
1280*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1281*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1282*bb4ee6a4SAndroid Build Coastguard Worker         }
1283*bb4ee6a4SAndroid Build Coastguard Worker     }
1284*bb4ee6a4SAndroid Build Coastguard Worker 
1285*bb4ee6a4SAndroid Build Coastguard Worker     /// Test vfio device's ACPI notification by simulating hardware triggering.
1286*bb4ee6a4SAndroid Build Coastguard Worker     /// When the signaling mechanism is set, the VFIO_IRQ_SET_DATA_BOOL can be used with
1287*bb4ee6a4SAndroid Build Coastguard Worker     /// VFIO_IRQ_SET_ACTION_TRIGGER to perform kernel level interrupt loopback testing.
acpi_notification_test(&self, index: u32, val: u32) -> Result<()>1288*bb4ee6a4SAndroid Build Coastguard Worker     pub fn acpi_notification_test(&self, index: u32, val: u32) -> Result<()> {
1289*bb4ee6a4SAndroid Build Coastguard Worker         let u32_size = mem::size_of::<u32>();
1290*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(1);
1291*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].argsz = (mem::size_of::<vfio_irq_set>() + u32_size) as u32;
1292*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].flags = VFIO_IRQ_SET_DATA_BOOL | VFIO_IRQ_SET_ACTION_TRIGGER;
1293*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].index = index;
1294*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].start = 0;
1295*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].count = 1;
1296*bb4ee6a4SAndroid Build Coastguard Worker 
1297*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1298*bb4ee6a4SAndroid Build Coastguard Worker         // It is safe as enough space is reserved through vec_with_array_field(u32)<count>.
1299*bb4ee6a4SAndroid Build Coastguard Worker         let data = unsafe { irq_set[0].data.as_mut_slice(u32_size) };
1300*bb4ee6a4SAndroid Build Coastguard Worker         data.copy_from_slice(&val.to_ne_bytes()[..]);
1301*bb4ee6a4SAndroid Build Coastguard Worker 
1302*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1303*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and irq_set which are valid value
1304*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS, &irq_set[0]) };
1305*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1306*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioAcpiNotificationTest(get_error()))
1307*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1308*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1309*bb4ee6a4SAndroid Build Coastguard Worker         }
1310*bb4ee6a4SAndroid Build Coastguard Worker     }
1311*bb4ee6a4SAndroid Build Coastguard Worker 
1312*bb4ee6a4SAndroid Build Coastguard Worker     /// Enable vfio device's irq and associate Irqfd Event with device.
1313*bb4ee6a4SAndroid Build Coastguard Worker     /// When MSIx is enabled, multi vectors will be supported, and vectors starting from subindex to
1314*bb4ee6a4SAndroid Build Coastguard Worker     /// subindex + descriptors length will be assigned with irqfd in the descriptors array.
1315*bb4ee6a4SAndroid Build Coastguard Worker     /// when index = VFIO_PCI_REQ_IRQ_INDEX, kernel vfio will trigger this event when physical
1316*bb4ee6a4SAndroid Build Coastguard Worker     /// device is removed.
1317*bb4ee6a4SAndroid Build Coastguard Worker     /// If descriptor is None, -1 is assigned to the irq. A value of -1 is used to either de-assign
1318*bb4ee6a4SAndroid Build Coastguard Worker     /// interrupts if already assigned or skip un-assigned interrupts.
irq_enable( &self, descriptors: &[Option<&Event>], index: u32, subindex: u32, ) -> Result<()>1319*bb4ee6a4SAndroid Build Coastguard Worker     pub fn irq_enable(
1320*bb4ee6a4SAndroid Build Coastguard Worker         &self,
1321*bb4ee6a4SAndroid Build Coastguard Worker         descriptors: &[Option<&Event>],
1322*bb4ee6a4SAndroid Build Coastguard Worker         index: u32,
1323*bb4ee6a4SAndroid Build Coastguard Worker         subindex: u32,
1324*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
1325*bb4ee6a4SAndroid Build Coastguard Worker         let count = descriptors.len();
1326*bb4ee6a4SAndroid Build Coastguard Worker         let u32_size = mem::size_of::<u32>();
1327*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(count);
1328*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].argsz = (mem::size_of::<vfio_irq_set>() + count * u32_size) as u32;
1329*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
1330*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].index = index;
1331*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].start = subindex;
1332*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].count = count as u32;
1333*bb4ee6a4SAndroid Build Coastguard Worker 
1334*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1335*bb4ee6a4SAndroid Build Coastguard Worker         // irq_set.data could be none, bool or descriptor according to flags, so irq_set.data
1336*bb4ee6a4SAndroid Build Coastguard Worker         // is u8 default, here irq_set.data is descriptor as u32, so 4 default u8 are combined
1337*bb4ee6a4SAndroid Build Coastguard Worker         // together as u32. It is safe as enough space is reserved through
1338*bb4ee6a4SAndroid Build Coastguard Worker         // vec_with_array_field(u32)<count>.
1339*bb4ee6a4SAndroid Build Coastguard Worker         let mut data = unsafe { irq_set[0].data.as_mut_slice(count * u32_size) };
1340*bb4ee6a4SAndroid Build Coastguard Worker         for descriptor in descriptors.iter().take(count) {
1341*bb4ee6a4SAndroid Build Coastguard Worker             let (left, right) = data.split_at_mut(u32_size);
1342*bb4ee6a4SAndroid Build Coastguard Worker             match descriptor {
1343*bb4ee6a4SAndroid Build Coastguard Worker                 Some(fd) => left.copy_from_slice(&fd.as_raw_descriptor().to_ne_bytes()[..]),
1344*bb4ee6a4SAndroid Build Coastguard Worker                 None => left.copy_from_slice(&(-1i32).to_ne_bytes()[..]),
1345*bb4ee6a4SAndroid Build Coastguard Worker             }
1346*bb4ee6a4SAndroid Build Coastguard Worker             data = right;
1347*bb4ee6a4SAndroid Build Coastguard Worker         }
1348*bb4ee6a4SAndroid Build Coastguard Worker 
1349*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1350*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and irq_set which are valid value
1351*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS, &irq_set[0]) };
1352*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1353*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioIrqEnable(get_error()))
1354*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1355*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1356*bb4ee6a4SAndroid Build Coastguard Worker         }
1357*bb4ee6a4SAndroid Build Coastguard Worker     }
1358*bb4ee6a4SAndroid Build Coastguard Worker 
1359*bb4ee6a4SAndroid Build Coastguard Worker     /// When intx is enabled, irqfd is used to trigger a level interrupt into guest, resample irqfd
1360*bb4ee6a4SAndroid Build Coastguard Worker     /// is used to get guest EOI notification.
1361*bb4ee6a4SAndroid Build Coastguard Worker     /// When host hw generates interrupt, vfio irq handler in host kernel receive and handle it,
1362*bb4ee6a4SAndroid Build Coastguard Worker     /// this handler disable hw irq first, then trigger irqfd to inject interrupt into guest. When
1363*bb4ee6a4SAndroid Build Coastguard Worker     /// resample irqfd is triggered by guest EOI, vfio kernel could enable hw irq, so hw could
1364*bb4ee6a4SAndroid Build Coastguard Worker     /// generate another interrupts.
1365*bb4ee6a4SAndroid Build Coastguard Worker     /// This function enable resample irqfd and let vfio kernel could get EOI notification.
1366*bb4ee6a4SAndroid Build Coastguard Worker     ///
1367*bb4ee6a4SAndroid Build Coastguard Worker     /// descriptor: should be resample IrqFd.
resample_virq_enable(&self, descriptor: &Event, index: u32) -> Result<()>1368*bb4ee6a4SAndroid Build Coastguard Worker     pub fn resample_virq_enable(&self, descriptor: &Event, index: u32) -> Result<()> {
1369*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(1);
1370*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].argsz = (mem::size_of::<vfio_irq_set>() + mem::size_of::<u32>()) as u32;
1371*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK;
1372*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].index = index;
1373*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].start = 0;
1374*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].count = 1;
1375*bb4ee6a4SAndroid Build Coastguard Worker 
1376*bb4ee6a4SAndroid Build Coastguard Worker         {
1377*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
1378*bb4ee6a4SAndroid Build Coastguard Worker             // irq_set.data could be none, bool or descriptor according to flags, so irq_set.data is
1379*bb4ee6a4SAndroid Build Coastguard Worker             // u8 default, here irq_set.data is descriptor as u32, so 4 default u8 are combined
1380*bb4ee6a4SAndroid Build Coastguard Worker             // together as u32. It is safe as enough space is reserved through
1381*bb4ee6a4SAndroid Build Coastguard Worker             // vec_with_array_field(u32)<1>.
1382*bb4ee6a4SAndroid Build Coastguard Worker             let descriptors = unsafe { irq_set[0].data.as_mut_slice(4) };
1383*bb4ee6a4SAndroid Build Coastguard Worker             descriptors.copy_from_slice(&descriptor.as_raw_descriptor().to_le_bytes()[..]);
1384*bb4ee6a4SAndroid Build Coastguard Worker         }
1385*bb4ee6a4SAndroid Build Coastguard Worker 
1386*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1387*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and irq_set which are valid value
1388*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS, &irq_set[0]) };
1389*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1390*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioIrqEnable(get_error()))
1391*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1392*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1393*bb4ee6a4SAndroid Build Coastguard Worker         }
1394*bb4ee6a4SAndroid Build Coastguard Worker     }
1395*bb4ee6a4SAndroid Build Coastguard Worker 
1396*bb4ee6a4SAndroid Build Coastguard Worker     /// disable vfio device's irq and disconnect Irqfd Event with device
irq_disable(&self, index: u32) -> Result<()>1397*bb4ee6a4SAndroid Build Coastguard Worker     pub fn irq_disable(&self, index: u32) -> Result<()> {
1398*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(0);
1399*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].argsz = mem::size_of::<vfio_irq_set>() as u32;
1400*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
1401*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].index = index;
1402*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].start = 0;
1403*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].count = 0;
1404*bb4ee6a4SAndroid Build Coastguard Worker 
1405*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1406*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and irq_set which are valid value
1407*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS, &irq_set[0]) };
1408*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1409*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioIrqDisable(get_error()))
1410*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1411*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1412*bb4ee6a4SAndroid Build Coastguard Worker         }
1413*bb4ee6a4SAndroid Build Coastguard Worker     }
1414*bb4ee6a4SAndroid Build Coastguard Worker 
1415*bb4ee6a4SAndroid Build Coastguard Worker     /// Unmask vfio device irq
irq_unmask(&self, index: u32) -> Result<()>1416*bb4ee6a4SAndroid Build Coastguard Worker     pub fn irq_unmask(&self, index: u32) -> Result<()> {
1417*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(0);
1418*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].argsz = mem::size_of::<vfio_irq_set>() as u32;
1419*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK;
1420*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].index = index;
1421*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].start = 0;
1422*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].count = 1;
1423*bb4ee6a4SAndroid Build Coastguard Worker 
1424*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1425*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and irq_set which are valid value
1426*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS, &irq_set[0]) };
1427*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1428*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioIrqUnmask(get_error()))
1429*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1430*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1431*bb4ee6a4SAndroid Build Coastguard Worker         }
1432*bb4ee6a4SAndroid Build Coastguard Worker     }
1433*bb4ee6a4SAndroid Build Coastguard Worker 
1434*bb4ee6a4SAndroid Build Coastguard Worker     /// Mask vfio device irq
irq_mask(&self, index: u32) -> Result<()>1435*bb4ee6a4SAndroid Build Coastguard Worker     pub fn irq_mask(&self, index: u32) -> Result<()> {
1436*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(0);
1437*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].argsz = mem::size_of::<vfio_irq_set>() as u32;
1438*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK;
1439*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].index = index;
1440*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].start = 0;
1441*bb4ee6a4SAndroid Build Coastguard Worker         irq_set[0].count = 1;
1442*bb4ee6a4SAndroid Build Coastguard Worker 
1443*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1444*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of self and irq_set which are valid value
1445*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS, &irq_set[0]) };
1446*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1447*bb4ee6a4SAndroid Build Coastguard Worker             Err(VfioError::VfioIrqMask(get_error()))
1448*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1449*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
1450*bb4ee6a4SAndroid Build Coastguard Worker         }
1451*bb4ee6a4SAndroid Build Coastguard Worker     }
1452*bb4ee6a4SAndroid Build Coastguard Worker 
1453*bb4ee6a4SAndroid Build Coastguard Worker     /// Get and validate VFIO device information.
get_device_info(device_file: &File) -> Result<(vfio_device_info, VfioDeviceType)>1454*bb4ee6a4SAndroid Build Coastguard Worker     fn get_device_info(device_file: &File) -> Result<(vfio_device_info, VfioDeviceType)> {
1455*bb4ee6a4SAndroid Build Coastguard Worker         let mut dev_info = vfio_device_info {
1456*bb4ee6a4SAndroid Build Coastguard Worker             argsz: mem::size_of::<vfio_device_info>() as u32,
1457*bb4ee6a4SAndroid Build Coastguard Worker             flags: 0,
1458*bb4ee6a4SAndroid Build Coastguard Worker             num_regions: 0,
1459*bb4ee6a4SAndroid Build Coastguard Worker             num_irqs: 0,
1460*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
1461*bb4ee6a4SAndroid Build Coastguard Worker         };
1462*bb4ee6a4SAndroid Build Coastguard Worker 
1463*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1464*bb4ee6a4SAndroid Build Coastguard Worker         // Safe as we are the owner of device_file and dev_info which are valid value,
1465*bb4ee6a4SAndroid Build Coastguard Worker         // and we verify the return value.
1466*bb4ee6a4SAndroid Build Coastguard Worker         let ret = unsafe { ioctl_with_mut_ref(device_file, VFIO_DEVICE_GET_INFO, &mut dev_info) };
1467*bb4ee6a4SAndroid Build Coastguard Worker         if ret < 0 {
1468*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::VfioDeviceGetInfo(get_error()));
1469*bb4ee6a4SAndroid Build Coastguard Worker         }
1470*bb4ee6a4SAndroid Build Coastguard Worker 
1471*bb4ee6a4SAndroid Build Coastguard Worker         let dev_type = if (dev_info.flags & VFIO_DEVICE_FLAGS_PCI) != 0 {
1472*bb4ee6a4SAndroid Build Coastguard Worker             if dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1
1473*bb4ee6a4SAndroid Build Coastguard Worker                 || dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1
1474*bb4ee6a4SAndroid Build Coastguard Worker             {
1475*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(VfioError::VfioDeviceGetInfo(get_error()));
1476*bb4ee6a4SAndroid Build Coastguard Worker             }
1477*bb4ee6a4SAndroid Build Coastguard Worker 
1478*bb4ee6a4SAndroid Build Coastguard Worker             VfioDeviceType::Pci
1479*bb4ee6a4SAndroid Build Coastguard Worker         } else if (dev_info.flags & VFIO_DEVICE_FLAGS_PLATFORM) != 0 {
1480*bb4ee6a4SAndroid Build Coastguard Worker             VfioDeviceType::Platform
1481*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1482*bb4ee6a4SAndroid Build Coastguard Worker             return Err(VfioError::UnknownDeviceType(dev_info.flags));
1483*bb4ee6a4SAndroid Build Coastguard Worker         };
1484*bb4ee6a4SAndroid Build Coastguard Worker 
1485*bb4ee6a4SAndroid Build Coastguard Worker         Ok((dev_info, dev_type))
1486*bb4ee6a4SAndroid Build Coastguard Worker     }
1487*bb4ee6a4SAndroid Build Coastguard Worker 
1488*bb4ee6a4SAndroid Build Coastguard Worker     /// Query interrupt information
1489*bb4ee6a4SAndroid Build Coastguard Worker     /// return: Vector of interrupts information, each of which contains flags and index
get_irqs(&self) -> Result<Vec<VfioIrq>>1490*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_irqs(&self) -> Result<Vec<VfioIrq>> {
1491*bb4ee6a4SAndroid Build Coastguard Worker         let mut irqs: Vec<VfioIrq> = Vec::new();
1492*bb4ee6a4SAndroid Build Coastguard Worker 
1493*bb4ee6a4SAndroid Build Coastguard Worker         for i in 0..self.num_irqs {
1494*bb4ee6a4SAndroid Build Coastguard Worker             let argsz = mem::size_of::<vfio_irq_info>() as u32;
1495*bb4ee6a4SAndroid Build Coastguard Worker             let mut irq_info = vfio_irq_info {
1496*bb4ee6a4SAndroid Build Coastguard Worker                 argsz,
1497*bb4ee6a4SAndroid Build Coastguard Worker                 flags: 0,
1498*bb4ee6a4SAndroid Build Coastguard Worker                 index: i,
1499*bb4ee6a4SAndroid Build Coastguard Worker                 count: 0,
1500*bb4ee6a4SAndroid Build Coastguard Worker             };
1501*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
1502*bb4ee6a4SAndroid Build Coastguard Worker             // Safe as we are the owner of dev and irq_info which are valid value,
1503*bb4ee6a4SAndroid Build Coastguard Worker             // and we verify the return value.
1504*bb4ee6a4SAndroid Build Coastguard Worker             let ret = unsafe {
1505*bb4ee6a4SAndroid Build Coastguard Worker                 ioctl_with_mut_ref(self.device_file(), VFIO_DEVICE_GET_IRQ_INFO, &mut irq_info)
1506*bb4ee6a4SAndroid Build Coastguard Worker             };
1507*bb4ee6a4SAndroid Build Coastguard Worker             if ret < 0 || irq_info.count != 1 {
1508*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(VfioError::VfioDeviceGetInfo(get_error()));
1509*bb4ee6a4SAndroid Build Coastguard Worker             }
1510*bb4ee6a4SAndroid Build Coastguard Worker 
1511*bb4ee6a4SAndroid Build Coastguard Worker             let irq = VfioIrq {
1512*bb4ee6a4SAndroid Build Coastguard Worker                 flags: irq_info.flags,
1513*bb4ee6a4SAndroid Build Coastguard Worker                 index: irq_info.index,
1514*bb4ee6a4SAndroid Build Coastguard Worker             };
1515*bb4ee6a4SAndroid Build Coastguard Worker             irqs.push(irq);
1516*bb4ee6a4SAndroid Build Coastguard Worker         }
1517*bb4ee6a4SAndroid Build Coastguard Worker         Ok(irqs)
1518*bb4ee6a4SAndroid Build Coastguard Worker     }
1519*bb4ee6a4SAndroid Build Coastguard Worker 
1520*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(clippy::cast_ptr_alignment)]
get_regions(dev: &File, num_regions: u32) -> Result<Vec<VfioRegion>>1521*bb4ee6a4SAndroid Build Coastguard Worker     fn get_regions(dev: &File, num_regions: u32) -> Result<Vec<VfioRegion>> {
1522*bb4ee6a4SAndroid Build Coastguard Worker         let mut regions: Vec<VfioRegion> = Vec::new();
1523*bb4ee6a4SAndroid Build Coastguard Worker         for i in 0..num_regions {
1524*bb4ee6a4SAndroid Build Coastguard Worker             let argsz = mem::size_of::<vfio_region_info>() as u32;
1525*bb4ee6a4SAndroid Build Coastguard Worker             let mut reg_info = vfio_region_info {
1526*bb4ee6a4SAndroid Build Coastguard Worker                 argsz,
1527*bb4ee6a4SAndroid Build Coastguard Worker                 flags: 0,
1528*bb4ee6a4SAndroid Build Coastguard Worker                 index: i,
1529*bb4ee6a4SAndroid Build Coastguard Worker                 cap_offset: 0,
1530*bb4ee6a4SAndroid Build Coastguard Worker                 size: 0,
1531*bb4ee6a4SAndroid Build Coastguard Worker                 offset: 0,
1532*bb4ee6a4SAndroid Build Coastguard Worker             };
1533*bb4ee6a4SAndroid Build Coastguard Worker             let ret =
1534*bb4ee6a4SAndroid Build Coastguard Worker                 // SAFETY:
1535*bb4ee6a4SAndroid Build Coastguard Worker                 // Safe as we are the owner of dev and reg_info which are valid value,
1536*bb4ee6a4SAndroid Build Coastguard Worker                 // and we verify the return value.
1537*bb4ee6a4SAndroid Build Coastguard Worker                 unsafe { ioctl_with_mut_ref(dev, VFIO_DEVICE_GET_REGION_INFO, &mut reg_info) };
1538*bb4ee6a4SAndroid Build Coastguard Worker             if ret < 0 {
1539*bb4ee6a4SAndroid Build Coastguard Worker                 continue;
1540*bb4ee6a4SAndroid Build Coastguard Worker             }
1541*bb4ee6a4SAndroid Build Coastguard Worker 
1542*bb4ee6a4SAndroid Build Coastguard Worker             let mut mmaps: Vec<vfio_region_sparse_mmap_area> = Vec::new();
1543*bb4ee6a4SAndroid Build Coastguard Worker             let mut cap_info: Option<(u32, u32)> = None;
1544*bb4ee6a4SAndroid Build Coastguard Worker             if reg_info.argsz > argsz {
1545*bb4ee6a4SAndroid Build Coastguard Worker                 let cap_len: usize = (reg_info.argsz - argsz) as usize;
1546*bb4ee6a4SAndroid Build Coastguard Worker                 let mut region_with_cap =
1547*bb4ee6a4SAndroid Build Coastguard Worker                     vec_with_array_field::<vfio_region_info_with_cap, u8>(cap_len);
1548*bb4ee6a4SAndroid Build Coastguard Worker                 region_with_cap[0].region_info.argsz = reg_info.argsz;
1549*bb4ee6a4SAndroid Build Coastguard Worker                 region_with_cap[0].region_info.flags = 0;
1550*bb4ee6a4SAndroid Build Coastguard Worker                 region_with_cap[0].region_info.index = i;
1551*bb4ee6a4SAndroid Build Coastguard Worker                 region_with_cap[0].region_info.cap_offset = 0;
1552*bb4ee6a4SAndroid Build Coastguard Worker                 region_with_cap[0].region_info.size = 0;
1553*bb4ee6a4SAndroid Build Coastguard Worker                 region_with_cap[0].region_info.offset = 0;
1554*bb4ee6a4SAndroid Build Coastguard Worker                 // SAFETY:
1555*bb4ee6a4SAndroid Build Coastguard Worker                 // Safe as we are the owner of dev and region_info which are valid value,
1556*bb4ee6a4SAndroid Build Coastguard Worker                 // and we verify the return value.
1557*bb4ee6a4SAndroid Build Coastguard Worker                 let ret = unsafe {
1558*bb4ee6a4SAndroid Build Coastguard Worker                     ioctl_with_mut_ref(
1559*bb4ee6a4SAndroid Build Coastguard Worker                         dev,
1560*bb4ee6a4SAndroid Build Coastguard Worker                         VFIO_DEVICE_GET_REGION_INFO,
1561*bb4ee6a4SAndroid Build Coastguard Worker                         &mut (region_with_cap[0].region_info),
1562*bb4ee6a4SAndroid Build Coastguard Worker                     )
1563*bb4ee6a4SAndroid Build Coastguard Worker                 };
1564*bb4ee6a4SAndroid Build Coastguard Worker                 if ret < 0 {
1565*bb4ee6a4SAndroid Build Coastguard Worker                     return Err(VfioError::VfioDeviceGetRegionInfo(get_error()));
1566*bb4ee6a4SAndroid Build Coastguard Worker                 }
1567*bb4ee6a4SAndroid Build Coastguard Worker 
1568*bb4ee6a4SAndroid Build Coastguard Worker                 if region_with_cap[0].region_info.flags & VFIO_REGION_INFO_FLAG_CAPS == 0 {
1569*bb4ee6a4SAndroid Build Coastguard Worker                     continue;
1570*bb4ee6a4SAndroid Build Coastguard Worker                 }
1571*bb4ee6a4SAndroid Build Coastguard Worker 
1572*bb4ee6a4SAndroid Build Coastguard Worker                 let cap_header_sz = mem::size_of::<vfio_info_cap_header>() as u32;
1573*bb4ee6a4SAndroid Build Coastguard Worker                 let mmap_cap_sz = mem::size_of::<vfio_region_info_cap_sparse_mmap>() as u32;
1574*bb4ee6a4SAndroid Build Coastguard Worker                 let mmap_area_sz = mem::size_of::<vfio_region_sparse_mmap_area>() as u32;
1575*bb4ee6a4SAndroid Build Coastguard Worker                 let type_cap_sz = mem::size_of::<vfio_region_info_cap_type>() as u32;
1576*bb4ee6a4SAndroid Build Coastguard Worker                 let region_info_sz = reg_info.argsz;
1577*bb4ee6a4SAndroid Build Coastguard Worker 
1578*bb4ee6a4SAndroid Build Coastguard Worker                 // region_with_cap[0].cap_info may contain many structures, like
1579*bb4ee6a4SAndroid Build Coastguard Worker                 // vfio_region_info_cap_sparse_mmap struct or vfio_region_info_cap_type struct.
1580*bb4ee6a4SAndroid Build Coastguard Worker                 // Both of them begin with vfio_info_cap_header, so we will get individual cap from
1581*bb4ee6a4SAndroid Build Coastguard Worker                 // vfio_into_cap_header.
1582*bb4ee6a4SAndroid Build Coastguard Worker                 // Go through all the cap structs.
1583*bb4ee6a4SAndroid Build Coastguard Worker                 let info_ptr = region_with_cap.as_ptr() as *mut u8;
1584*bb4ee6a4SAndroid Build Coastguard Worker                 let mut offset = region_with_cap[0].region_info.cap_offset;
1585*bb4ee6a4SAndroid Build Coastguard Worker                 while offset != 0 {
1586*bb4ee6a4SAndroid Build Coastguard Worker                     if offset + cap_header_sz > region_info_sz {
1587*bb4ee6a4SAndroid Build Coastguard Worker                         break;
1588*bb4ee6a4SAndroid Build Coastguard Worker                     }
1589*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY:
1590*bb4ee6a4SAndroid Build Coastguard Worker                     // Safe, as cap_header struct is in this function allocated region_with_cap
1591*bb4ee6a4SAndroid Build Coastguard Worker                     // vec.
1592*bb4ee6a4SAndroid Build Coastguard Worker                     let cap_ptr = unsafe { info_ptr.offset(offset as isize) };
1593*bb4ee6a4SAndroid Build Coastguard Worker                     // SAFETY:
1594*bb4ee6a4SAndroid Build Coastguard Worker                     // Safe, as cap_header struct is in this function allocated region_with_cap
1595*bb4ee6a4SAndroid Build Coastguard Worker                     // vec.
1596*bb4ee6a4SAndroid Build Coastguard Worker                     let cap_header = unsafe { &*(cap_ptr as *const vfio_info_cap_header) };
1597*bb4ee6a4SAndroid Build Coastguard Worker                     if cap_header.id as u32 == VFIO_REGION_INFO_CAP_SPARSE_MMAP {
1598*bb4ee6a4SAndroid Build Coastguard Worker                         if offset + mmap_cap_sz > region_info_sz {
1599*bb4ee6a4SAndroid Build Coastguard Worker                             break;
1600*bb4ee6a4SAndroid Build Coastguard Worker                         }
1601*bb4ee6a4SAndroid Build Coastguard Worker                         // cap_ptr is vfio_region_info_cap_sparse_mmap here
1602*bb4ee6a4SAndroid Build Coastguard Worker                         let sparse_mmap =
1603*bb4ee6a4SAndroid Build Coastguard Worker                             // SAFETY:
1604*bb4ee6a4SAndroid Build Coastguard Worker                             // Safe, this vfio_region_info_cap_sparse_mmap is in this function
1605*bb4ee6a4SAndroid Build Coastguard Worker                             // allocated region_with_cap vec.
1606*bb4ee6a4SAndroid Build Coastguard Worker                             unsafe { &*(cap_ptr as *const vfio_region_info_cap_sparse_mmap) };
1607*bb4ee6a4SAndroid Build Coastguard Worker 
1608*bb4ee6a4SAndroid Build Coastguard Worker                         let area_num = sparse_mmap.nr_areas;
1609*bb4ee6a4SAndroid Build Coastguard Worker                         if offset + mmap_cap_sz + area_num * mmap_area_sz > region_info_sz {
1610*bb4ee6a4SAndroid Build Coastguard Worker                             break;
1611*bb4ee6a4SAndroid Build Coastguard Worker                         }
1612*bb4ee6a4SAndroid Build Coastguard Worker                         let areas =
1613*bb4ee6a4SAndroid Build Coastguard Worker                             // SAFETY:
1614*bb4ee6a4SAndroid Build Coastguard Worker                             // Safe, these vfio_region_sparse_mmap_area are in this function allocated
1615*bb4ee6a4SAndroid Build Coastguard Worker                             // region_with_cap vec.
1616*bb4ee6a4SAndroid Build Coastguard Worker                             unsafe { sparse_mmap.areas.as_slice(sparse_mmap.nr_areas as usize) };
1617*bb4ee6a4SAndroid Build Coastguard Worker                         for area in areas.iter() {
1618*bb4ee6a4SAndroid Build Coastguard Worker                             mmaps.push(*area);
1619*bb4ee6a4SAndroid Build Coastguard Worker                         }
1620*bb4ee6a4SAndroid Build Coastguard Worker                     } else if cap_header.id as u32 == VFIO_REGION_INFO_CAP_TYPE {
1621*bb4ee6a4SAndroid Build Coastguard Worker                         if offset + type_cap_sz > region_info_sz {
1622*bb4ee6a4SAndroid Build Coastguard Worker                             break;
1623*bb4ee6a4SAndroid Build Coastguard Worker                         }
1624*bb4ee6a4SAndroid Build Coastguard Worker                         // cap_ptr is vfio_region_info_cap_type here
1625*bb4ee6a4SAndroid Build Coastguard Worker                         let cap_type_info =
1626*bb4ee6a4SAndroid Build Coastguard Worker                             // SAFETY:
1627*bb4ee6a4SAndroid Build Coastguard Worker                             // Safe, this vfio_region_info_cap_type is in this function allocated
1628*bb4ee6a4SAndroid Build Coastguard Worker                             // region_with_cap vec
1629*bb4ee6a4SAndroid Build Coastguard Worker                             unsafe { &*(cap_ptr as *const vfio_region_info_cap_type) };
1630*bb4ee6a4SAndroid Build Coastguard Worker 
1631*bb4ee6a4SAndroid Build Coastguard Worker                         cap_info = Some((cap_type_info.type_, cap_type_info.subtype));
1632*bb4ee6a4SAndroid Build Coastguard Worker                     } else if cap_header.id as u32 == VFIO_REGION_INFO_CAP_MSIX_MAPPABLE {
1633*bb4ee6a4SAndroid Build Coastguard Worker                         mmaps.push(vfio_region_sparse_mmap_area {
1634*bb4ee6a4SAndroid Build Coastguard Worker                             offset: 0,
1635*bb4ee6a4SAndroid Build Coastguard Worker                             size: region_with_cap[0].region_info.size,
1636*bb4ee6a4SAndroid Build Coastguard Worker                         });
1637*bb4ee6a4SAndroid Build Coastguard Worker                     }
1638*bb4ee6a4SAndroid Build Coastguard Worker 
1639*bb4ee6a4SAndroid Build Coastguard Worker                     offset = cap_header.next;
1640*bb4ee6a4SAndroid Build Coastguard Worker                 }
1641*bb4ee6a4SAndroid Build Coastguard Worker             } else if reg_info.flags & VFIO_REGION_INFO_FLAG_MMAP != 0 {
1642*bb4ee6a4SAndroid Build Coastguard Worker                 mmaps.push(vfio_region_sparse_mmap_area {
1643*bb4ee6a4SAndroid Build Coastguard Worker                     offset: 0,
1644*bb4ee6a4SAndroid Build Coastguard Worker                     size: reg_info.size,
1645*bb4ee6a4SAndroid Build Coastguard Worker                 });
1646*bb4ee6a4SAndroid Build Coastguard Worker             }
1647*bb4ee6a4SAndroid Build Coastguard Worker 
1648*bb4ee6a4SAndroid Build Coastguard Worker             let region = VfioRegion {
1649*bb4ee6a4SAndroid Build Coastguard Worker                 flags: reg_info.flags,
1650*bb4ee6a4SAndroid Build Coastguard Worker                 size: reg_info.size,
1651*bb4ee6a4SAndroid Build Coastguard Worker                 offset: reg_info.offset,
1652*bb4ee6a4SAndroid Build Coastguard Worker                 mmaps,
1653*bb4ee6a4SAndroid Build Coastguard Worker                 cap_info,
1654*bb4ee6a4SAndroid Build Coastguard Worker             };
1655*bb4ee6a4SAndroid Build Coastguard Worker             regions.push(region);
1656*bb4ee6a4SAndroid Build Coastguard Worker         }
1657*bb4ee6a4SAndroid Build Coastguard Worker 
1658*bb4ee6a4SAndroid Build Coastguard Worker         Ok(regions)
1659*bb4ee6a4SAndroid Build Coastguard Worker     }
1660*bb4ee6a4SAndroid Build Coastguard Worker 
1661*bb4ee6a4SAndroid Build Coastguard Worker     /// get a region's flag
1662*bb4ee6a4SAndroid Build Coastguard Worker     /// the return's value may conatin:
1663*bb4ee6a4SAndroid Build Coastguard Worker     ///     VFIO_REGION_INFO_FLAG_READ:  region supports read
1664*bb4ee6a4SAndroid Build Coastguard Worker     ///     VFIO_REGION_INFO_FLAG_WRITE: region supports write
1665*bb4ee6a4SAndroid Build Coastguard Worker     ///     VFIO_REGION_INFO_FLAG_MMAP:  region supports mmap
1666*bb4ee6a4SAndroid Build Coastguard Worker     ///     VFIO_REGION_INFO_FLAG_CAPS:  region's info supports caps
get_region_flags(&self, index: usize) -> u321667*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_region_flags(&self, index: usize) -> u32 {
1668*bb4ee6a4SAndroid Build Coastguard Worker         match self.regions.get(index) {
1669*bb4ee6a4SAndroid Build Coastguard Worker             Some(v) => v.flags,
1670*bb4ee6a4SAndroid Build Coastguard Worker             None => {
1671*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("get_region_flags() with invalid index: {}", index);
1672*bb4ee6a4SAndroid Build Coastguard Worker                 0
1673*bb4ee6a4SAndroid Build Coastguard Worker             }
1674*bb4ee6a4SAndroid Build Coastguard Worker         }
1675*bb4ee6a4SAndroid Build Coastguard Worker     }
1676*bb4ee6a4SAndroid Build Coastguard Worker 
1677*bb4ee6a4SAndroid Build Coastguard Worker     /// get a region's offset
1678*bb4ee6a4SAndroid Build Coastguard Worker     /// return: Region offset from the start of vfio device descriptor
get_region_offset(&self, index: usize) -> u641679*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_region_offset(&self, index: usize) -> u64 {
1680*bb4ee6a4SAndroid Build Coastguard Worker         match self.regions.get(index) {
1681*bb4ee6a4SAndroid Build Coastguard Worker             Some(v) => v.offset,
1682*bb4ee6a4SAndroid Build Coastguard Worker             None => {
1683*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("get_region_offset with invalid index: {}", index);
1684*bb4ee6a4SAndroid Build Coastguard Worker                 0
1685*bb4ee6a4SAndroid Build Coastguard Worker             }
1686*bb4ee6a4SAndroid Build Coastguard Worker         }
1687*bb4ee6a4SAndroid Build Coastguard Worker     }
1688*bb4ee6a4SAndroid Build Coastguard Worker 
1689*bb4ee6a4SAndroid Build Coastguard Worker     /// get a region's size
1690*bb4ee6a4SAndroid Build Coastguard Worker     /// return: Region size from the start of vfio device descriptor
get_region_size(&self, index: usize) -> u641691*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_region_size(&self, index: usize) -> u64 {
1692*bb4ee6a4SAndroid Build Coastguard Worker         match self.regions.get(index) {
1693*bb4ee6a4SAndroid Build Coastguard Worker             Some(v) => v.size,
1694*bb4ee6a4SAndroid Build Coastguard Worker             None => {
1695*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("get_region_size with invalid index: {}", index);
1696*bb4ee6a4SAndroid Build Coastguard Worker                 0
1697*bb4ee6a4SAndroid Build Coastguard Worker             }
1698*bb4ee6a4SAndroid Build Coastguard Worker         }
1699*bb4ee6a4SAndroid Build Coastguard Worker     }
1700*bb4ee6a4SAndroid Build Coastguard Worker 
1701*bb4ee6a4SAndroid Build Coastguard Worker     /// get a number of regions
1702*bb4ee6a4SAndroid Build Coastguard Worker     /// return: Number of regions of vfio device descriptor
get_region_count(&self) -> usize1703*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_region_count(&self) -> usize {
1704*bb4ee6a4SAndroid Build Coastguard Worker         self.regions.len()
1705*bb4ee6a4SAndroid Build Coastguard Worker     }
1706*bb4ee6a4SAndroid Build Coastguard Worker 
1707*bb4ee6a4SAndroid Build Coastguard Worker     /// get a region's mmap info vector
get_region_mmap(&self, index: usize) -> Vec<vfio_region_sparse_mmap_area>1708*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_region_mmap(&self, index: usize) -> Vec<vfio_region_sparse_mmap_area> {
1709*bb4ee6a4SAndroid Build Coastguard Worker         match self.regions.get(index) {
1710*bb4ee6a4SAndroid Build Coastguard Worker             Some(v) => v.mmaps.clone(),
1711*bb4ee6a4SAndroid Build Coastguard Worker             None => {
1712*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("get_region_mmap with invalid index: {}", index);
1713*bb4ee6a4SAndroid Build Coastguard Worker                 Vec::new()
1714*bb4ee6a4SAndroid Build Coastguard Worker             }
1715*bb4ee6a4SAndroid Build Coastguard Worker         }
1716*bb4ee6a4SAndroid Build Coastguard Worker     }
1717*bb4ee6a4SAndroid Build Coastguard Worker 
1718*bb4ee6a4SAndroid Build Coastguard Worker     /// find the specified cap type in device regions
1719*bb4ee6a4SAndroid Build Coastguard Worker     /// Input:
1720*bb4ee6a4SAndroid Build Coastguard Worker     ///      type_:  cap type
1721*bb4ee6a4SAndroid Build Coastguard Worker     ///      sub_type: cap sub_type
1722*bb4ee6a4SAndroid Build Coastguard Worker     /// Output:
1723*bb4ee6a4SAndroid Build Coastguard Worker     ///     None: device doesn't have the specified cap type
1724*bb4ee6a4SAndroid Build Coastguard Worker     ///     Some((bar_index, region_size)): device has the specified cap type, return region's
1725*bb4ee6a4SAndroid Build Coastguard Worker     ///                                     index and size
get_cap_type_info(&self, type_: u32, sub_type: u32) -> Option<(u32, u64)>1726*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_cap_type_info(&self, type_: u32, sub_type: u32) -> Option<(u32, u64)> {
1727*bb4ee6a4SAndroid Build Coastguard Worker         for (index, region) in self.regions.iter().enumerate() {
1728*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(cap_info) = &region.cap_info {
1729*bb4ee6a4SAndroid Build Coastguard Worker                 if cap_info.0 == type_ && cap_info.1 == sub_type {
1730*bb4ee6a4SAndroid Build Coastguard Worker                     return Some((index as u32, region.size));
1731*bb4ee6a4SAndroid Build Coastguard Worker                 }
1732*bb4ee6a4SAndroid Build Coastguard Worker             }
1733*bb4ee6a4SAndroid Build Coastguard Worker         }
1734*bb4ee6a4SAndroid Build Coastguard Worker 
1735*bb4ee6a4SAndroid Build Coastguard Worker         None
1736*bb4ee6a4SAndroid Build Coastguard Worker     }
1737*bb4ee6a4SAndroid Build Coastguard Worker 
1738*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns file offset corresponding to the given `VfioRegionAddr`.
1739*bb4ee6a4SAndroid Build Coastguard Worker     /// The offset can be used when reading/writing the VFIO device's FD directly.
get_offset_for_addr(&self, addr: &VfioRegionAddr) -> Result<u64>1740*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_offset_for_addr(&self, addr: &VfioRegionAddr) -> Result<u64> {
1741*bb4ee6a4SAndroid Build Coastguard Worker         let region = self
1742*bb4ee6a4SAndroid Build Coastguard Worker             .regions
1743*bb4ee6a4SAndroid Build Coastguard Worker             .get(addr.index)
1744*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(VfioError::InvalidIndex(addr.index))?;
1745*bb4ee6a4SAndroid Build Coastguard Worker         Ok(region.offset + addr.addr)
1746*bb4ee6a4SAndroid Build Coastguard Worker     }
1747*bb4ee6a4SAndroid Build Coastguard Worker 
1748*bb4ee6a4SAndroid Build Coastguard Worker     /// Read region's data from VFIO device into buf
1749*bb4ee6a4SAndroid Build Coastguard Worker     /// index: region num
1750*bb4ee6a4SAndroid Build Coastguard Worker     /// buf: data destination and buf length is read size
1751*bb4ee6a4SAndroid Build Coastguard Worker     /// addr: offset in the region
region_read(&self, index: usize, buf: &mut [u8], addr: u64)1752*bb4ee6a4SAndroid Build Coastguard Worker     pub fn region_read(&self, index: usize, buf: &mut [u8], addr: u64) {
1753*bb4ee6a4SAndroid Build Coastguard Worker         let stub: &VfioRegion = self
1754*bb4ee6a4SAndroid Build Coastguard Worker             .regions
1755*bb4ee6a4SAndroid Build Coastguard Worker             .get(index)
1756*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap_or_else(|| panic!("tried to read VFIO with an invalid index: {}", index));
1757*bb4ee6a4SAndroid Build Coastguard Worker 
1758*bb4ee6a4SAndroid Build Coastguard Worker         let size = buf.len() as u64;
1759*bb4ee6a4SAndroid Build Coastguard Worker         if size > stub.size || addr + size > stub.size {
1760*bb4ee6a4SAndroid Build Coastguard Worker             panic!(
1761*bb4ee6a4SAndroid Build Coastguard Worker                 "tried to read VFIO region with invalid arguments: index={}, addr=0x{:x}, size=0x{:x}",
1762*bb4ee6a4SAndroid Build Coastguard Worker                 index, addr, size
1763*bb4ee6a4SAndroid Build Coastguard Worker             );
1764*bb4ee6a4SAndroid Build Coastguard Worker         }
1765*bb4ee6a4SAndroid Build Coastguard Worker 
1766*bb4ee6a4SAndroid Build Coastguard Worker         self.dev
1767*bb4ee6a4SAndroid Build Coastguard Worker             .read_exact_at(buf, stub.offset + addr)
1768*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap_or_else(|e| {
1769*bb4ee6a4SAndroid Build Coastguard Worker                 panic!(
1770*bb4ee6a4SAndroid Build Coastguard Worker                     "failed to read region: index={}, addr=0x{:x}, error={}",
1771*bb4ee6a4SAndroid Build Coastguard Worker                     index, addr, e
1772*bb4ee6a4SAndroid Build Coastguard Worker                 )
1773*bb4ee6a4SAndroid Build Coastguard Worker             });
1774*bb4ee6a4SAndroid Build Coastguard Worker     }
1775*bb4ee6a4SAndroid Build Coastguard Worker 
1776*bb4ee6a4SAndroid Build Coastguard Worker     /// Reads a value from the specified `VfioRegionAddr.addr` + `offset`.
region_read_from_addr<T: FromBytes>(&self, addr: &VfioRegionAddr, offset: u64) -> T1777*bb4ee6a4SAndroid Build Coastguard Worker     pub fn region_read_from_addr<T: FromBytes>(&self, addr: &VfioRegionAddr, offset: u64) -> T {
1778*bb4ee6a4SAndroid Build Coastguard Worker         let mut val = mem::MaybeUninit::zeroed();
1779*bb4ee6a4SAndroid Build Coastguard Worker         let buf =
1780*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY:
1781*bb4ee6a4SAndroid Build Coastguard Worker             // Safe because we have zero-initialized `size_of::<T>()` bytes.
1782*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { slice::from_raw_parts_mut(val.as_mut_ptr() as *mut u8, mem::size_of::<T>()) };
1783*bb4ee6a4SAndroid Build Coastguard Worker         self.region_read(addr.index, buf, addr.addr + offset);
1784*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
1785*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because any bit pattern is valid for a type that implements FromBytes.
1786*bb4ee6a4SAndroid Build Coastguard Worker         unsafe { val.assume_init() }
1787*bb4ee6a4SAndroid Build Coastguard Worker     }
1788*bb4ee6a4SAndroid Build Coastguard Worker 
1789*bb4ee6a4SAndroid Build Coastguard Worker     /// write the data from buf into a vfio device region
1790*bb4ee6a4SAndroid Build Coastguard Worker     /// index: region num
1791*bb4ee6a4SAndroid Build Coastguard Worker     /// buf: data src and buf length is write size
1792*bb4ee6a4SAndroid Build Coastguard Worker     /// addr: offset in the region
region_write(&self, index: usize, buf: &[u8], addr: u64)1793*bb4ee6a4SAndroid Build Coastguard Worker     pub fn region_write(&self, index: usize, buf: &[u8], addr: u64) {
1794*bb4ee6a4SAndroid Build Coastguard Worker         let stub: &VfioRegion = self
1795*bb4ee6a4SAndroid Build Coastguard Worker             .regions
1796*bb4ee6a4SAndroid Build Coastguard Worker             .get(index)
1797*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap_or_else(|| panic!("tried to write VFIO with an invalid index: {}", index));
1798*bb4ee6a4SAndroid Build Coastguard Worker 
1799*bb4ee6a4SAndroid Build Coastguard Worker         let size = buf.len() as u64;
1800*bb4ee6a4SAndroid Build Coastguard Worker         if size > stub.size
1801*bb4ee6a4SAndroid Build Coastguard Worker             || addr + size > stub.size
1802*bb4ee6a4SAndroid Build Coastguard Worker             || (stub.flags & VFIO_REGION_INFO_FLAG_WRITE) == 0
1803*bb4ee6a4SAndroid Build Coastguard Worker         {
1804*bb4ee6a4SAndroid Build Coastguard Worker             panic!(
1805*bb4ee6a4SAndroid Build Coastguard Worker                 "tried to write VFIO region with invalid arguments: index={}, addr=0x{:x}, size=0x{:x}",
1806*bb4ee6a4SAndroid Build Coastguard Worker                 index, addr, size
1807*bb4ee6a4SAndroid Build Coastguard Worker             );
1808*bb4ee6a4SAndroid Build Coastguard Worker         }
1809*bb4ee6a4SAndroid Build Coastguard Worker 
1810*bb4ee6a4SAndroid Build Coastguard Worker         self.dev
1811*bb4ee6a4SAndroid Build Coastguard Worker             .write_all_at(buf, stub.offset + addr)
1812*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap_or_else(|e| {
1813*bb4ee6a4SAndroid Build Coastguard Worker                 panic!(
1814*bb4ee6a4SAndroid Build Coastguard Worker                     "failed to write region: index={}, addr=0x{:x}, error={}",
1815*bb4ee6a4SAndroid Build Coastguard Worker                     index, addr, e
1816*bb4ee6a4SAndroid Build Coastguard Worker                 )
1817*bb4ee6a4SAndroid Build Coastguard Worker             });
1818*bb4ee6a4SAndroid Build Coastguard Worker     }
1819*bb4ee6a4SAndroid Build Coastguard Worker 
1820*bb4ee6a4SAndroid Build Coastguard Worker     /// Writes data into the specified `VfioRegionAddr.addr` + `offset`.
region_write_to_addr<T: AsBytes>(&self, val: &T, addr: &VfioRegionAddr, offset: u64)1821*bb4ee6a4SAndroid Build Coastguard Worker     pub fn region_write_to_addr<T: AsBytes>(&self, val: &T, addr: &VfioRegionAddr, offset: u64) {
1822*bb4ee6a4SAndroid Build Coastguard Worker         self.region_write(addr.index, val.as_bytes(), addr.addr + offset);
1823*bb4ee6a4SAndroid Build Coastguard Worker     }
1824*bb4ee6a4SAndroid Build Coastguard Worker 
1825*bb4ee6a4SAndroid Build Coastguard Worker     /// get vfio device's descriptors which are passed into minijail process
keep_rds(&self) -> Vec<RawDescriptor>1826*bb4ee6a4SAndroid Build Coastguard Worker     pub fn keep_rds(&self) -> Vec<RawDescriptor> {
1827*bb4ee6a4SAndroid Build Coastguard Worker         vec![
1828*bb4ee6a4SAndroid Build Coastguard Worker             self.dev.as_raw_descriptor(),
1829*bb4ee6a4SAndroid Build Coastguard Worker             self.group_descriptor,
1830*bb4ee6a4SAndroid Build Coastguard Worker             self.container.lock().as_raw_descriptor(),
1831*bb4ee6a4SAndroid Build Coastguard Worker         ]
1832*bb4ee6a4SAndroid Build Coastguard Worker     }
1833*bb4ee6a4SAndroid Build Coastguard Worker 
1834*bb4ee6a4SAndroid Build Coastguard Worker     /// Add (iova, user_addr) map into vfio container iommu table
1835*bb4ee6a4SAndroid Build Coastguard Worker     /// # Safety
1836*bb4ee6a4SAndroid Build Coastguard Worker     ///
1837*bb4ee6a4SAndroid Build Coastguard Worker     /// The caller is responsible for determining the safety of the VFIO_IOMMU_MAP_DMA ioctl.
vfio_dma_map( &self, iova: u64, size: u64, user_addr: u64, write_en: bool, ) -> Result<()>1838*bb4ee6a4SAndroid Build Coastguard Worker     pub unsafe fn vfio_dma_map(
1839*bb4ee6a4SAndroid Build Coastguard Worker         &self,
1840*bb4ee6a4SAndroid Build Coastguard Worker         iova: u64,
1841*bb4ee6a4SAndroid Build Coastguard Worker         size: u64,
1842*bb4ee6a4SAndroid Build Coastguard Worker         user_addr: u64,
1843*bb4ee6a4SAndroid Build Coastguard Worker         write_en: bool,
1844*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
1845*bb4ee6a4SAndroid Build Coastguard Worker         self.container
1846*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
1847*bb4ee6a4SAndroid Build Coastguard Worker             .vfio_dma_map(iova, size, user_addr, write_en)
1848*bb4ee6a4SAndroid Build Coastguard Worker     }
1849*bb4ee6a4SAndroid Build Coastguard Worker 
1850*bb4ee6a4SAndroid Build Coastguard Worker     /// Remove (iova, user_addr) map from vfio container iommu table
vfio_dma_unmap(&self, iova: u64, size: u64) -> Result<()>1851*bb4ee6a4SAndroid Build Coastguard Worker     pub fn vfio_dma_unmap(&self, iova: u64, size: u64) -> Result<()> {
1852*bb4ee6a4SAndroid Build Coastguard Worker         self.container.lock().vfio_dma_unmap(iova, size)
1853*bb4ee6a4SAndroid Build Coastguard Worker     }
1854*bb4ee6a4SAndroid Build Coastguard Worker 
vfio_get_iommu_page_size_mask(&self) -> Result<u64>1855*bb4ee6a4SAndroid Build Coastguard Worker     pub fn vfio_get_iommu_page_size_mask(&self) -> Result<u64> {
1856*bb4ee6a4SAndroid Build Coastguard Worker         self.container.lock().vfio_get_iommu_page_size_mask()
1857*bb4ee6a4SAndroid Build Coastguard Worker     }
1858*bb4ee6a4SAndroid Build Coastguard Worker 
alloc_iova(&self, size: u64, align_size: u64, alloc: Alloc) -> Result<u64>1859*bb4ee6a4SAndroid Build Coastguard Worker     pub fn alloc_iova(&self, size: u64, align_size: u64, alloc: Alloc) -> Result<u64> {
1860*bb4ee6a4SAndroid Build Coastguard Worker         self.iova_alloc
1861*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
1862*bb4ee6a4SAndroid Build Coastguard Worker             .allocate_with_align(size, alloc, "alloc_iova".to_owned(), align_size)
1863*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(VfioError::Resources)
1864*bb4ee6a4SAndroid Build Coastguard Worker     }
1865*bb4ee6a4SAndroid Build Coastguard Worker 
get_iova(&self, alloc: &Alloc) -> Option<AddressRange>1866*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_iova(&self, alloc: &Alloc) -> Option<AddressRange> {
1867*bb4ee6a4SAndroid Build Coastguard Worker         self.iova_alloc.lock().get(alloc).map(|res| res.0)
1868*bb4ee6a4SAndroid Build Coastguard Worker     }
1869*bb4ee6a4SAndroid Build Coastguard Worker 
release_iova(&self, alloc: Alloc) -> Result<AddressRange>1870*bb4ee6a4SAndroid Build Coastguard Worker     pub fn release_iova(&self, alloc: Alloc) -> Result<AddressRange> {
1871*bb4ee6a4SAndroid Build Coastguard Worker         self.iova_alloc
1872*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
1873*bb4ee6a4SAndroid Build Coastguard Worker             .release(alloc)
1874*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(VfioError::Resources)
1875*bb4ee6a4SAndroid Build Coastguard Worker     }
1876*bb4ee6a4SAndroid Build Coastguard Worker 
get_max_addr(&self) -> u641877*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_max_addr(&self) -> u64 {
1878*bb4ee6a4SAndroid Build Coastguard Worker         self.iova_alloc.lock().get_max_addr()
1879*bb4ee6a4SAndroid Build Coastguard Worker     }
1880*bb4ee6a4SAndroid Build Coastguard Worker 
1881*bb4ee6a4SAndroid Build Coastguard Worker     /// Gets the vfio device backing `File`.
device_file(&self) -> &File1882*bb4ee6a4SAndroid Build Coastguard Worker     pub fn device_file(&self) -> &File {
1883*bb4ee6a4SAndroid Build Coastguard Worker         &self.dev
1884*bb4ee6a4SAndroid Build Coastguard Worker     }
1885*bb4ee6a4SAndroid Build Coastguard Worker 
1886*bb4ee6a4SAndroid Build Coastguard Worker     /// close vfio device
close(&self)1887*bb4ee6a4SAndroid Build Coastguard Worker     pub fn close(&self) {
1888*bb4ee6a4SAndroid Build Coastguard Worker         self.container.lock().remove_group(self.group_id, true);
1889*bb4ee6a4SAndroid Build Coastguard Worker     }
1890*bb4ee6a4SAndroid Build Coastguard Worker }
1891*bb4ee6a4SAndroid Build Coastguard Worker 
1892*bb4ee6a4SAndroid Build Coastguard Worker pub struct VfioPciConfig {
1893*bb4ee6a4SAndroid Build Coastguard Worker     device: Arc<VfioDevice>,
1894*bb4ee6a4SAndroid Build Coastguard Worker }
1895*bb4ee6a4SAndroid Build Coastguard Worker 
1896*bb4ee6a4SAndroid Build Coastguard Worker impl VfioPciConfig {
new(device: Arc<VfioDevice>) -> Self1897*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(device: Arc<VfioDevice>) -> Self {
1898*bb4ee6a4SAndroid Build Coastguard Worker         VfioPciConfig { device }
1899*bb4ee6a4SAndroid Build Coastguard Worker     }
1900*bb4ee6a4SAndroid Build Coastguard Worker 
read_config<T: FromBytes>(&self, offset: u32) -> T1901*bb4ee6a4SAndroid Build Coastguard Worker     pub fn read_config<T: FromBytes>(&self, offset: u32) -> T {
1902*bb4ee6a4SAndroid Build Coastguard Worker         let mut buf = vec![0u8; std::mem::size_of::<T>()];
1903*bb4ee6a4SAndroid Build Coastguard Worker         self.device.region_read(
1904*bb4ee6a4SAndroid Build Coastguard Worker             VFIO_PCI_CONFIG_REGION_INDEX as usize,
1905*bb4ee6a4SAndroid Build Coastguard Worker             &mut buf,
1906*bb4ee6a4SAndroid Build Coastguard Worker             offset.into(),
1907*bb4ee6a4SAndroid Build Coastguard Worker         );
1908*bb4ee6a4SAndroid Build Coastguard Worker         T::read_from(&buf[..]).expect("failed to convert config data from slice")
1909*bb4ee6a4SAndroid Build Coastguard Worker     }
1910*bb4ee6a4SAndroid Build Coastguard Worker 
write_config<T: AsBytes>(&self, config: T, offset: u32)1911*bb4ee6a4SAndroid Build Coastguard Worker     pub fn write_config<T: AsBytes>(&self, config: T, offset: u32) {
1912*bb4ee6a4SAndroid Build Coastguard Worker         self.device.region_write(
1913*bb4ee6a4SAndroid Build Coastguard Worker             VFIO_PCI_CONFIG_REGION_INDEX as usize,
1914*bb4ee6a4SAndroid Build Coastguard Worker             config.as_bytes(),
1915*bb4ee6a4SAndroid Build Coastguard Worker             offset.into(),
1916*bb4ee6a4SAndroid Build Coastguard Worker         );
1917*bb4ee6a4SAndroid Build Coastguard Worker     }
1918*bb4ee6a4SAndroid Build Coastguard Worker 
1919*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the VFIO device this config refers to as the bus master.
set_bus_master(&self)1920*bb4ee6a4SAndroid Build Coastguard Worker     pub fn set_bus_master(&self) {
1921*bb4ee6a4SAndroid Build Coastguard Worker         /// Constant definitions from `linux/pci_regs.h`.
1922*bb4ee6a4SAndroid Build Coastguard Worker         const PCI_COMMAND: u32 = 0x4;
1923*bb4ee6a4SAndroid Build Coastguard Worker         /// Enable bus mastering
1924*bb4ee6a4SAndroid Build Coastguard Worker         const PCI_COMMAND_MASTER: u16 = 0x4;
1925*bb4ee6a4SAndroid Build Coastguard Worker 
1926*bb4ee6a4SAndroid Build Coastguard Worker         let mut cmd: u16 = self.read_config(PCI_COMMAND);
1927*bb4ee6a4SAndroid Build Coastguard Worker 
1928*bb4ee6a4SAndroid Build Coastguard Worker         if cmd & PCI_COMMAND_MASTER != 0 {
1929*bb4ee6a4SAndroid Build Coastguard Worker             return;
1930*bb4ee6a4SAndroid Build Coastguard Worker         }
1931*bb4ee6a4SAndroid Build Coastguard Worker 
1932*bb4ee6a4SAndroid Build Coastguard Worker         cmd |= PCI_COMMAND_MASTER;
1933*bb4ee6a4SAndroid Build Coastguard Worker 
1934*bb4ee6a4SAndroid Build Coastguard Worker         self.write_config(cmd, PCI_COMMAND);
1935*bb4ee6a4SAndroid Build Coastguard Worker     }
1936*bb4ee6a4SAndroid Build Coastguard Worker }
1937*bb4ee6a4SAndroid Build Coastguard Worker 
1938*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for VfioDevice {
as_raw_descriptor(&self) -> RawDescriptor1939*bb4ee6a4SAndroid Build Coastguard Worker     fn as_raw_descriptor(&self) -> RawDescriptor {
1940*bb4ee6a4SAndroid Build Coastguard Worker         self.dev.as_raw_descriptor()
1941*bb4ee6a4SAndroid Build Coastguard Worker     }
1942*bb4ee6a4SAndroid Build Coastguard Worker }
1943