mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-02 11:35:46 +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"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "vhost_rs"
|
name = "vhost_rs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1049,6 +1073,7 @@ dependencies = [
|
|||||||
"net_util 0.1.0",
|
"net_util 0.1.0",
|
||||||
"pci 0.1.0",
|
"pci 0.1.0",
|
||||||
"qcow 0.1.0",
|
"qcow 0.1.0",
|
||||||
|
"vfio 0.0.1",
|
||||||
"vm-allocator 0.1.0",
|
"vm-allocator 0.1.0",
|
||||||
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
"vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)",
|
||||||
"vm-virtio 0.1.0",
|
"vm-virtio 0.1.0",
|
||||||
|
@ -100,6 +100,13 @@ fn main() {
|
|||||||
.help("Control (virtio) console: off|tty|file=/path/to/a/file")
|
.help("Control (virtio) console: off|tty|file=/path/to/a/file")
|
||||||
.default_value("tty"),
|
.default_value("tty"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("device")
|
||||||
|
.long("device")
|
||||||
|
.help("Direct device assignment parameter")
|
||||||
|
.takes_value(true)
|
||||||
|
.min_values(1),
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
// These .unwrap()s cannot fail as there is a default value defined
|
// 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 console = cmd_arguments.value_of("console").unwrap();
|
||||||
let fs: Option<Vec<&str>> = cmd_arguments.values_of("fs").map(|x| x.collect());
|
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 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 {
|
let vm_config = match config::VmConfig::parse(config::VmParams {
|
||||||
cpus,
|
cpus,
|
||||||
@ -131,6 +139,7 @@ fn main() {
|
|||||||
pmem,
|
pmem,
|
||||||
serial,
|
serial,
|
||||||
console,
|
console,
|
||||||
|
devices,
|
||||||
}) {
|
}) {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -15,6 +15,7 @@ log = "*"
|
|||||||
net_util = { path = "../net_util" }
|
net_util = { path = "../net_util" }
|
||||||
pci = {path = "../pci"}
|
pci = {path = "../pci"}
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
|
vfio = { path = "../vfio" }
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vm-allocator = { path = "../vm-allocator" }
|
vm-allocator = { path = "../vm-allocator" }
|
||||||
vmm-sys-util = { git = "https://github.com/rust-vmm/vmm-sys-util" }
|
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 pmem: Option<Vec<&'a str>>,
|
||||||
pub serial: &'a str,
|
pub serial: &'a str,
|
||||||
pub console: &'a str,
|
pub console: &'a str,
|
||||||
|
pub devices: Option<Vec<&'a str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_size(size: &str) -> Result<u64> {
|
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 struct VmConfig<'a> {
|
||||||
pub cpus: CpusConfig,
|
pub cpus: CpusConfig,
|
||||||
pub memory: MemoryConfig<'a>,
|
pub memory: MemoryConfig<'a>,
|
||||||
@ -391,6 +405,7 @@ pub struct VmConfig<'a> {
|
|||||||
pub pmem: Option<Vec<PmemConfig<'a>>>,
|
pub pmem: Option<Vec<PmemConfig<'a>>>,
|
||||||
pub serial: ConsoleConfig<'a>,
|
pub serial: ConsoleConfig<'a>,
|
||||||
pub console: ConsoleConfig<'a>,
|
pub console: ConsoleConfig<'a>,
|
||||||
|
pub devices: Option<Vec<DeviceConfig<'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VmConfig<'a> {
|
impl<'a> VmConfig<'a> {
|
||||||
@ -437,6 +452,15 @@ impl<'a> VmConfig<'a> {
|
|||||||
return Err(Error::ParseTTYParam);
|
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 {
|
Ok(VmConfig {
|
||||||
cpus: CpusConfig::parse(vm_params.cpus)?,
|
cpus: CpusConfig::parse(vm_params.cpus)?,
|
||||||
memory: MemoryConfig::parse(vm_params.memory)?,
|
memory: MemoryConfig::parse(vm_params.memory)?,
|
||||||
@ -449,6 +473,7 @@ impl<'a> VmConfig<'a> {
|
|||||||
pmem,
|
pmem,
|
||||||
serial,
|
serial,
|
||||||
console,
|
console,
|
||||||
|
devices,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ extern crate kvm_ioctls;
|
|||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate linux_loader;
|
extern crate linux_loader;
|
||||||
extern crate net_util;
|
extern crate net_util;
|
||||||
|
extern crate vfio;
|
||||||
extern crate vm_allocator;
|
extern crate vm_allocator;
|
||||||
extern crate vm_memory;
|
extern crate vm_memory;
|
||||||
extern crate vm_virtio;
|
extern crate vm_virtio;
|
||||||
@ -45,6 +46,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
|
|||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
use std::sync::{Arc, Barrier, Mutex};
|
use std::sync::{Arc, Barrier, Mutex};
|
||||||
use std::{result, str, thread};
|
use std::{result, str, thread};
|
||||||
|
use vfio::{VfioDevice, VfioPciDevice, VfioPciError};
|
||||||
use vm_allocator::{GsiApic, SystemAllocator};
|
use vm_allocator::{GsiApic, SystemAllocator};
|
||||||
use vm_memory::guest_memory::FileOffset;
|
use vm_memory::guest_memory::FileOffset;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
@ -245,6 +247,15 @@ pub enum DeviceManagerError {
|
|||||||
|
|
||||||
/// Error creating console output file
|
/// Error creating console output file
|
||||||
ConsoleOutputFileOpen(io::Error),
|
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>;
|
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
|
||||||
|
|
||||||
@ -513,6 +524,7 @@ impl DeviceManager {
|
|||||||
vm_cfg: &VmConfig,
|
vm_cfg: &VmConfig,
|
||||||
msi_capable: bool,
|
msi_capable: bool,
|
||||||
userspace_ioapic: bool,
|
userspace_ioapic: bool,
|
||||||
|
mem_slots: u32,
|
||||||
) -> DeviceManagerResult<Self> {
|
) -> DeviceManagerResult<Self> {
|
||||||
let mut io_bus = devices::Bus::new();
|
let mut io_bus = devices::Bus::new();
|
||||||
let mut mmio_bus = devices::Bus::new();
|
let mut mmio_bus = devices::Bus::new();
|
||||||
@ -608,6 +620,16 @@ impl DeviceManager {
|
|||||||
&interrupt_info,
|
&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));
|
let pci = Arc::new(Mutex::new(pci));
|
||||||
|
|
||||||
Ok(DeviceManager {
|
Ok(DeviceManager {
|
||||||
@ -924,6 +946,43 @@ impl DeviceManager {
|
|||||||
Ok(())
|
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(
|
fn add_virtio_pci_device(
|
||||||
virtio_device: Box<vm_virtio::VirtioDevice>,
|
virtio_device: Box<vm_virtio::VirtioDevice>,
|
||||||
memory: GuestMemoryMmap,
|
memory: GuestMemoryMmap,
|
||||||
@ -1322,6 +1381,7 @@ impl<'a> Vm<'a> {
|
|||||||
&config,
|
&config,
|
||||||
msi_capable,
|
msi_capable,
|
||||||
userspace_ioapic,
|
userspace_ioapic,
|
||||||
|
arch_mem_regions.len() as u32,
|
||||||
)
|
)
|
||||||
.map_err(Error::DeviceManager)?;
|
.map_err(Error::DeviceManager)?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user