mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-11 04:26:38 +00:00
devices: vfio: create KVM_DEV_TYPE_VFIO device from linux.rs
One KVM_DEV_TYPE_VFIO instance may be created per VM. Currently this device is created from VfioContainer::init(), which makes it not able to create multiple vfio container. This patch creates the KVM_DEV_TYPE_VFIO virtual device before creating any VfioContainer or VfioDevice instances, and passes it into the VfioDevice constructor where it's actually used. In this way, it's possible to create multiple VFIO containers BUG=b:181736020 TEST=passthru multiple devices and create more than one VFIO containers Change-Id: I4b4e4941363efa91f2217af385f4f00eadd041c5 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2976053 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: David Stevens <stevensd@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: David Stevens <stevensd@chromium.org>
This commit is contained in:
parent
f7979867d6
commit
5deee48856
2 changed files with 30 additions and 25 deletions
|
@ -19,7 +19,6 @@ use base::{
|
|||
ioctl, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref, ioctl_with_val, warn,
|
||||
AsRawDescriptor, Error, Event, FromRawDescriptor, RawDescriptor, SafeDescriptor,
|
||||
};
|
||||
use hypervisor::{DeviceKind, Vm};
|
||||
use vm_memory::GuestMemory;
|
||||
|
||||
use vfio_sys::*;
|
||||
|
@ -35,7 +34,6 @@ pub enum VfioError {
|
|||
GroupSetContainer(Error),
|
||||
ContainerSetIOMMU(Error),
|
||||
GroupGetDeviceFD(Error),
|
||||
CreateVfioKvmDevice(Error),
|
||||
KvmSetDeviceAttr(Error),
|
||||
VfioDeviceGetInfo(Error),
|
||||
VfioDeviceGetRegionInfo(Error),
|
||||
|
@ -60,7 +58,6 @@ impl fmt::Display for VfioError {
|
|||
VfioError::GroupSetContainer(e) => write!(f, "failed to add vfio group into vfio container: {}", e),
|
||||
VfioError::ContainerSetIOMMU(e) => write!(f, "failed to set container's IOMMU driver type as VfioType1V2: {}", e),
|
||||
VfioError::GroupGetDeviceFD(e) => write!(f, "failed to get vfio device fd: {}", e),
|
||||
VfioError::CreateVfioKvmDevice(e) => write!(f, "failed to create KVM vfio device: {}", e),
|
||||
VfioError::KvmSetDeviceAttr(e) => write!(f, "failed to set KVM vfio device's attribute: {}", e),
|
||||
VfioError::VfioDeviceGetInfo(e) => write!(f, "failed to get vfio device's info or info doesn't match: {}", e),
|
||||
VfioError::VfioDeviceGetRegionInfo(e) => write!(f, "failed to get vfio device's region info: {}", e),
|
||||
|
@ -82,7 +79,6 @@ fn get_error() -> Error {
|
|||
/// VfioContainer contain multi VfioGroup, and delegate an IOMMU domain table
|
||||
pub struct VfioContainer {
|
||||
container: File,
|
||||
kvm_vfio_dev: Option<SafeDescriptor>,
|
||||
groups: HashMap<u32, Arc<VfioGroup>>,
|
||||
}
|
||||
|
||||
|
@ -104,7 +100,6 @@ impl VfioContainer {
|
|||
|
||||
Ok(VfioContainer {
|
||||
container,
|
||||
kvm_vfio_dev: None,
|
||||
groups: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
@ -163,7 +158,7 @@ impl VfioContainer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn init(&mut self, vm: &impl Vm, guest_mem: &GuestMemory) -> Result<(), VfioError> {
|
||||
fn init(&mut self, guest_mem: &GuestMemory) -> Result<(), VfioError> {
|
||||
if !self.check_extension(VFIO_TYPE1v2_IOMMU) {
|
||||
return Err(VfioError::VfioType1V2);
|
||||
}
|
||||
|
@ -179,19 +174,14 @@ impl VfioContainer {
|
|||
unsafe { self.vfio_dma_map(guest_addr.0, size as u64, host_addr as u64) }
|
||||
})?;
|
||||
|
||||
let vfio_descriptor = vm
|
||||
.create_device(DeviceKind::Vfio)
|
||||
.map_err(VfioError::CreateVfioKvmDevice)?;
|
||||
self.kvm_vfio_dev = Some(vfio_descriptor);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_group(
|
||||
&mut self,
|
||||
id: u32,
|
||||
vm: &impl Vm,
|
||||
guest_mem: &GuestMemory,
|
||||
kvm_vfio_file: &SafeDescriptor,
|
||||
) -> Result<Arc<VfioGroup>, VfioError> {
|
||||
match self.groups.get(&id) {
|
||||
Some(group) => Ok(group.clone()),
|
||||
|
@ -201,13 +191,9 @@ impl VfioContainer {
|
|||
if self.groups.is_empty() {
|
||||
// Before the first group is added into container, do once cotainer
|
||||
// initialize for a vm
|
||||
self.init(vm, guest_mem)?;
|
||||
self.init(guest_mem)?;
|
||||
}
|
||||
|
||||
let kvm_vfio_file = self
|
||||
.kvm_vfio_dev
|
||||
.as_ref()
|
||||
.expect("kvm vfio device should exist");
|
||||
group.kvm_device_add_group(kvm_vfio_file)?;
|
||||
|
||||
self.groups.insert(id, group.clone());
|
||||
|
@ -351,10 +337,12 @@ impl VfioDevice {
|
|||
/// Create a new vfio device, then guest read/write on this device could be
|
||||
/// transfered into kernel vfio.
|
||||
/// sysfspath specify the vfio device path in sys file system.
|
||||
/// kvm_vfio_file specify a valid file descriptor returned from KVM_CREATE_DEVICE
|
||||
/// with type KVM_DEV_TYPE_VFIO
|
||||
pub fn new(
|
||||
sysfspath: &Path,
|
||||
vm: &impl Vm,
|
||||
guest_mem: &GuestMemory,
|
||||
kvm_vfio_file: &SafeDescriptor,
|
||||
container: Arc<Mutex<VfioContainer>>,
|
||||
) -> Result<Self, VfioError> {
|
||||
let mut uuid_path = PathBuf::new();
|
||||
|
@ -367,7 +355,9 @@ impl VfioDevice {
|
|||
.parse::<u32>()
|
||||
.map_err(|_| VfioError::InvalidPath)?;
|
||||
|
||||
let group = container.lock().get_group(group_id, vm, guest_mem)?;
|
||||
let group = container
|
||||
.lock()
|
||||
.get_group(group_id, guest_mem, kvm_vfio_file)?;
|
||||
let name_osstr = sysfspath.file_name().ok_or(VfioError::InvalidPath)?;
|
||||
let name_str = name_osstr.to_str().ok_or(VfioError::InvalidPath)?;
|
||||
let name = String::from(name_str);
|
||||
|
|
27
src/linux.rs
27
src/linux.rs
|
@ -51,7 +51,7 @@ use devices::{
|
|||
#[cfg(feature = "usb")]
|
||||
use devices::{HostBackendDeviceProvider, XhciController};
|
||||
use hypervisor::kvm::{Kvm, KvmVcpu, KvmVm};
|
||||
use hypervisor::{HypervisorCap, Vcpu, VcpuExit, VcpuRunHandle, Vm, VmCap};
|
||||
use hypervisor::{DeviceKind, HypervisorCap, Vcpu, VcpuExit, VcpuRunHandle, Vm, VmCap};
|
||||
use minijail::{self, Minijail};
|
||||
use net_util::{Error as NetError, MacAddress, Tap};
|
||||
use remain::sorted;
|
||||
|
@ -124,6 +124,7 @@ pub enum Error {
|
|||
CreateUsbProvider(devices::usb::host_backend::error::Error),
|
||||
CreateVcpu(base::Error),
|
||||
CreateVfioDevice(devices::vfio::VfioError),
|
||||
CreateVfioKvmDevice(base::Error),
|
||||
CreateVm(base::Error),
|
||||
CreateWaitContext(base::Error),
|
||||
DeviceJail(minijail::Error),
|
||||
|
@ -253,6 +254,7 @@ impl Display for Error {
|
|||
CreateUsbProvider(e) => write!(f, "failed to create usb provider: {}", e),
|
||||
CreateVcpu(e) => write!(f, "failed to create vcpu: {}", e),
|
||||
CreateVfioDevice(e) => write!(f, "Failed to create vfio device {}", e),
|
||||
CreateVfioKvmDevice(e) => write!(f, "failed to create KVM vfio device: {}", e),
|
||||
CreateVm(e) => write!(f, "failed to create vm: {}", e),
|
||||
CreateWaitContext(e) => write!(f, "failed to create wait context: {}", e),
|
||||
DeviceJail(e) => write!(f, "failed to jail device: {}", e),
|
||||
|
@ -1735,6 +1737,7 @@ fn create_vfio_device(
|
|||
resources: &mut SystemAllocator,
|
||||
control_tubes: &mut Vec<TaggedControlTube>,
|
||||
vfio_path: &Path,
|
||||
kvm_vfio_file: &SafeDescriptor,
|
||||
) -> DeviceResult<(Box<VfioPciDevice>, Option<Minijail>)> {
|
||||
let vfio_container =
|
||||
VFIO_CONTAINER.with::<_, DeviceResult<Arc<Mutex<VfioContainer>>>>(|v| {
|
||||
|
@ -1763,7 +1766,7 @@ fn create_vfio_device(
|
|||
let (vfio_host_tube_mem, vfio_device_tube_mem) = Tube::pair().map_err(Error::CreateTube)?;
|
||||
control_tubes.push(TaggedControlTube::VmMemory(vfio_host_tube_mem));
|
||||
|
||||
let vfio_device = VfioDevice::new(vfio_path, vm, vm.get_memory(), vfio_container)
|
||||
let vfio_device = VfioDevice::new(vfio_path, vm.get_memory(), &kvm_vfio_file, vfio_container)
|
||||
.map_err(Error::CreateVfioDevice)?;
|
||||
let mut vfio_pci_device = Box::new(VfioPciDevice::new(
|
||||
vfio_device,
|
||||
|
@ -1837,10 +1840,22 @@ fn create_devices(
|
|||
pci_devices.push((usb_controller, simple_jail(&cfg, "xhci")?));
|
||||
}
|
||||
|
||||
for vfio_path in &cfg.vfio {
|
||||
let (vfio_pci_device, jail) =
|
||||
create_vfio_device(cfg, vm, resources, control_tubes, vfio_path.as_path())?;
|
||||
pci_devices.push((vfio_pci_device, jail));
|
||||
if !cfg.vfio.is_empty() {
|
||||
let kvm_vfio_file = vm
|
||||
.create_device(DeviceKind::Vfio)
|
||||
.map_err(Error::CreateVfioKvmDevice)?;
|
||||
|
||||
for vfio_path in &cfg.vfio {
|
||||
let (vfio_pci_device, jail) = create_vfio_device(
|
||||
cfg,
|
||||
vm,
|
||||
resources,
|
||||
control_tubes,
|
||||
vfio_path.as_path(),
|
||||
&kvm_vfio_file,
|
||||
)?;
|
||||
pci_devices.push((vfio_pci_device, jail));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(pci_devices)
|
||||
|
|
Loading…
Reference in a new issue