mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
vmm: Support direct device assignment
With the VFIO crate, we can now support directly assigned PCI devices into cloud-hypervisor guests. We support assigning multiple host devices, through the --device command line parameter. This parameter takes the host device sysfs path. Fixes: #60 Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
b746dd7116
commit
4d16ca8ae7
25
Cargo.lock
generated
25
Cargo.lock
generated
@ -982,6 +982,30 @@ name = "vec_map"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vfio"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"devices 0.1.0",
|
||||
"kvm-bindings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kvm-ioctls 0.2.0 (git+https://github.com/rust-vmm/kvm-ioctls)",
|
||||
"libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pci 0.1.0",
|
||||
"vfio-bindings 0.0.1",
|
||||
"vm-allocator 0.1.0",
|
||||
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
||||
"vmm-sys-util 0.1.0 (git+https://github.com/rust-vmm/vmm-sys-util)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vfio-bindings"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"vmm-sys-util 0.1.0 (git+https://github.com/rust-vmm/vmm-sys-util)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vhost_rs"
|
||||
version = "0.1.0"
|
||||
@ -1049,6 +1073,7 @@ dependencies = [
|
||||
"net_util 0.1.0",
|
||||
"pci 0.1.0",
|
||||
"qcow 0.1.0",
|
||||
"vfio 0.0.1",
|
||||
"vm-allocator 0.1.0",
|
||||
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
||||
"vm-virtio 0.1.0",
|
||||
|
@ -100,6 +100,13 @@ fn main() {
|
||||
.help("Control (virtio) console: off|tty|file=/path/to/a/file")
|
||||
.default_value("tty"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("device")
|
||||
.long("device")
|
||||
.help("Direct device assignment parameter")
|
||||
.takes_value(true)
|
||||
.min_values(1),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
// These .unwrap()s cannot fail as there is a default value defined
|
||||
@ -118,6 +125,7 @@ fn main() {
|
||||
let console = cmd_arguments.value_of("console").unwrap();
|
||||
let fs: Option<Vec<&str>> = cmd_arguments.values_of("fs").map(|x| x.collect());
|
||||
let pmem: Option<Vec<&str>> = cmd_arguments.values_of("pmem").map(|x| x.collect());
|
||||
let devices: Option<Vec<&str>> = cmd_arguments.values_of("device").map(|x| x.collect());
|
||||
|
||||
let vm_config = match config::VmConfig::parse(config::VmParams {
|
||||
cpus,
|
||||
@ -131,6 +139,7 @@ fn main() {
|
||||
pmem,
|
||||
serial,
|
||||
console,
|
||||
devices,
|
||||
}) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
|
@ -15,6 +15,7 @@ log = "*"
|
||||
net_util = { path = "../net_util" }
|
||||
pci = {path = "../pci"}
|
||||
qcow = { path = "../qcow" }
|
||||
vfio = { path = "../vfio" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vmm-sys-util = { git = "https://github.com/rust-vmm/vmm-sys-util" }
|
||||
|
@ -69,6 +69,7 @@ pub struct VmParams<'a> {
|
||||
pub pmem: Option<Vec<&'a str>>,
|
||||
pub serial: &'a str,
|
||||
pub console: &'a str,
|
||||
pub devices: Option<Vec<&'a str>>,
|
||||
}
|
||||
|
||||
fn parse_size(size: &str) -> Result<u64> {
|
||||
@ -379,6 +380,19 @@ impl<'a> ConsoleConfig<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceConfig<'a> {
|
||||
pub path: &'a Path,
|
||||
}
|
||||
|
||||
impl<'a> DeviceConfig<'a> {
|
||||
pub fn parse(device: &'a str) -> Result<Self> {
|
||||
Ok(DeviceConfig {
|
||||
path: Path::new(device),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VmConfig<'a> {
|
||||
pub cpus: CpusConfig,
|
||||
pub memory: MemoryConfig<'a>,
|
||||
@ -391,6 +405,7 @@ pub struct VmConfig<'a> {
|
||||
pub pmem: Option<Vec<PmemConfig<'a>>>,
|
||||
pub serial: ConsoleConfig<'a>,
|
||||
pub console: ConsoleConfig<'a>,
|
||||
pub devices: Option<Vec<DeviceConfig<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a> VmConfig<'a> {
|
||||
@ -437,6 +452,15 @@ impl<'a> VmConfig<'a> {
|
||||
return Err(Error::ParseTTYParam);
|
||||
}
|
||||
|
||||
let mut devices: Option<Vec<DeviceConfig>> = None;
|
||||
if let Some(device_list) = &vm_params.devices {
|
||||
let mut device_config_list = Vec::new();
|
||||
for item in device_list.iter() {
|
||||
device_config_list.push(DeviceConfig::parse(item)?);
|
||||
}
|
||||
devices = Some(device_config_list);
|
||||
}
|
||||
|
||||
Ok(VmConfig {
|
||||
cpus: CpusConfig::parse(vm_params.cpus)?,
|
||||
memory: MemoryConfig::parse(vm_params.memory)?,
|
||||
@ -449,6 +473,7 @@ impl<'a> VmConfig<'a> {
|
||||
pmem,
|
||||
serial,
|
||||
console,
|
||||
devices,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ extern crate kvm_ioctls;
|
||||
extern crate libc;
|
||||
extern crate linux_loader;
|
||||
extern crate net_util;
|
||||
extern crate vfio;
|
||||
extern crate vm_allocator;
|
||||
extern crate vm_memory;
|
||||
extern crate vm_virtio;
|
||||
@ -45,6 +46,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use std::{result, str, thread};
|
||||
use vfio::{VfioDevice, VfioPciDevice, VfioPciError};
|
||||
use vm_allocator::{GsiApic, SystemAllocator};
|
||||
use vm_memory::guest_memory::FileOffset;
|
||||
use vm_memory::{
|
||||
@ -245,6 +247,15 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Error creating console output file
|
||||
ConsoleOutputFileOpen(io::Error),
|
||||
|
||||
/// Cannot create a VFIO device
|
||||
VfioCreate(vfio::VfioError),
|
||||
|
||||
/// Cannot create a VFIO PCI device
|
||||
VfioPciCreate(vfio::VfioPciError),
|
||||
|
||||
/// Failed to map VFIO MMIO region.
|
||||
VfioMapRegion(VfioPciError),
|
||||
}
|
||||
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
|
||||
|
||||
@ -513,6 +524,7 @@ impl DeviceManager {
|
||||
vm_cfg: &VmConfig,
|
||||
msi_capable: bool,
|
||||
userspace_ioapic: bool,
|
||||
mem_slots: u32,
|
||||
) -> DeviceManagerResult<Self> {
|
||||
let mut io_bus = devices::Bus::new();
|
||||
let mut mmio_bus = devices::Bus::new();
|
||||
@ -608,6 +620,16 @@ impl DeviceManager {
|
||||
&interrupt_info,
|
||||
)?;
|
||||
|
||||
DeviceManager::add_vfio_devices(
|
||||
memory.clone(),
|
||||
allocator,
|
||||
vm_fd,
|
||||
&vm_cfg,
|
||||
&mut pci,
|
||||
&mut buses,
|
||||
mem_slots,
|
||||
)?;
|
||||
|
||||
let pci = Arc::new(Mutex::new(pci));
|
||||
|
||||
Ok(DeviceManager {
|
||||
@ -924,6 +946,43 @@ impl DeviceManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_vfio_devices(
|
||||
memory: GuestMemoryMmap,
|
||||
allocator: &mut SystemAllocator,
|
||||
vm_fd: &Arc<VmFd>,
|
||||
vm_cfg: &VmConfig,
|
||||
pci: &mut PciConfigIo,
|
||||
buses: &mut BusInfo,
|
||||
mem_slots: u32,
|
||||
) -> DeviceManagerResult<()> {
|
||||
if let Some(device_list_cfg) = &vm_cfg.devices {
|
||||
for device_cfg in device_list_cfg.iter() {
|
||||
let vfio_device = VfioDevice::new(device_cfg.path, vm_fd, memory.clone())
|
||||
.map_err(DeviceManagerError::VfioCreate)?;
|
||||
|
||||
let mut vfio_pci_device = VfioPciDevice::new(vm_fd, allocator, vfio_device)
|
||||
.map_err(DeviceManagerError::VfioPciCreate)?;
|
||||
|
||||
let bars = vfio_pci_device
|
||||
.allocate_bars(allocator)
|
||||
.map_err(DeviceManagerError::AllocateBars)?;
|
||||
|
||||
vfio_pci_device
|
||||
.map_mmio_regions(vm_fd, mem_slots)
|
||||
.map_err(DeviceManagerError::VfioMapRegion)?;
|
||||
|
||||
let vfio_pci_device = Arc::new(Mutex::new(vfio_pci_device));
|
||||
|
||||
pci.add_device(vfio_pci_device.clone())
|
||||
.map_err(DeviceManagerError::AddPciDevice)?;
|
||||
|
||||
pci.register_mapping(vfio_pci_device.clone(), buses.io, buses.mmio, bars)
|
||||
.map_err(DeviceManagerError::AddPciDevice)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_virtio_pci_device(
|
||||
virtio_device: Box<vm_virtio::VirtioDevice>,
|
||||
memory: GuestMemoryMmap,
|
||||
@ -1322,6 +1381,7 @@ impl<'a> Vm<'a> {
|
||||
&config,
|
||||
msi_capable,
|
||||
userspace_ioapic,
|
||||
arch_mem_regions.len() as u32,
|
||||
)
|
||||
.map_err(Error::DeviceManager)?;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user