linux: Convert all virtio devices to PCI

Change the main create_virtio_devs() function to create virtio devices
using the PCI transport rather than MMIO.

BUG=chromium:854766
TEST=Boot crosvm and verify that all virtio devices still work

Change-Id: I9a6e60b21edea1e5ac2b3ae5c91793d45cf5063a
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1241541
Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
Daniel Verkamp 2018-09-24 15:00:36 -07:00 committed by chrome-bot
parent a158e31038
commit d635acbaf3
7 changed files with 47 additions and 42 deletions

2
Cargo.lock generated
View file

@ -16,6 +16,7 @@ dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"data_model 0.1.0", "data_model 0.1.0",
"devices 0.1.0", "devices 0.1.0",
"io_jail 0.1.0",
"kernel_cmdline 0.1.0", "kernel_cmdline 0.1.0",
"kvm 0.1.0", "kvm 0.1.0",
"kvm_sys 0.1.0", "kvm_sys 0.1.0",
@ -439,6 +440,7 @@ dependencies = [
"cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"data_model 0.1.0", "data_model 0.1.0",
"devices 0.1.0", "devices 0.1.0",
"io_jail 0.1.0",
"kernel_cmdline 0.1.0", "kernel_cmdline 0.1.0",
"kernel_loader 0.1.0", "kernel_loader 0.1.0",
"kvm 0.1.0", "kvm 0.1.0",

View file

@ -7,6 +7,7 @@ authors = ["The Chromium OS Authors"]
arch = { path = "../arch" } arch = { path = "../arch" }
data_model = { path = "../data_model" } data_model = { path = "../data_model" }
devices = { path = "../devices" } devices = { path = "../devices" }
io_jail = { path = "../io_jail" }
kernel_cmdline = { path = "../kernel_cmdline" } kernel_cmdline = { path = "../kernel_cmdline" }
kvm_sys = { path = "../kvm_sys" } kvm_sys = { path = "../kvm_sys" }
kvm = { path = "../kvm" } kvm = { path = "../kvm" }

View file

@ -6,6 +6,7 @@ extern crate arch;
extern crate byteorder; extern crate byteorder;
extern crate data_model; extern crate data_model;
extern crate devices; extern crate devices;
extern crate io_jail;
extern crate kernel_cmdline; extern crate kernel_cmdline;
extern crate kvm; extern crate kvm;
extern crate kvm_sys; extern crate kvm_sys;
@ -22,8 +23,9 @@ use std::sync::{Arc, Mutex};
use std::os::unix::io::FromRawFd; use std::os::unix::io::FromRawFd;
use std::os::unix::net::UnixDatagram; use std::os::unix::net::UnixDatagram;
use arch::{RunnableLinuxVm, VirtioDeviceStub, VmComponents}; use arch::{RunnableLinuxVm, VmComponents};
use devices::{Bus, BusError, PciConfigMmio, PciInterruptPin}; use devices::{Bus, BusError, PciConfigMmio, PciDevice, PciInterruptPin};
use io_jail::Minijail;
use sys_util::{EventFd, GuestAddress, GuestMemory}; use sys_util::{EventFd, GuestAddress, GuestMemory};
use resources::{AddressRanges, SystemAllocator}; use resources::{AddressRanges, SystemAllocator};
@ -193,7 +195,7 @@ pub struct AArch64;
impl arch::LinuxArch for AArch64 { impl arch::LinuxArch for AArch64 {
fn build_vm<F>(mut components: VmComponents, virtio_devs: F) -> Result<RunnableLinuxVm> fn build_vm<F>(mut components: VmComponents, virtio_devs: F) -> Result<RunnableLinuxVm>
where where
F: FnOnce(&GuestMemory, &EventFd) -> Result<Vec<VirtioDeviceStub>> F: FnOnce(&GuestMemory, &EventFd) -> Result<Vec<(Box<PciDevice + 'static>, Minijail)>>
{ {
let mut resources = Self::get_resource_allocator(components.memory_mb, let mut resources = Self::get_resource_allocator(components.memory_mb,
components.wayland_dmabuf); components.wayland_dmabuf);
@ -216,27 +218,20 @@ impl arch::LinuxArch for AArch64 {
let mut mmio_bus = devices::Bus::new(); let mut mmio_bus = devices::Bus::new();
let (pci, pci_irqs) = arch::generate_pci_root(components.pci_devices, let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?;
let pci_devices = virtio_devs(&mem, &exit_evt)?;
let (pci, pci_irqs) = arch::generate_pci_root(pci_devices,
&mut mmio_bus, &mut mmio_bus,
&mut resources, &mut resources,
&mut vm) &mut vm)
.map_err(Error::CreatePciRoot)?; .map_err(Error::CreatePciRoot)?;
let pci_bus = Arc::new(Mutex::new(PciConfigMmio::new(pci))); let pci_bus = Arc::new(Mutex::new(PciConfigMmio::new(pci)));
let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?;
let (io_bus, stdio_serial) = Self::setup_io_bus()?; let (io_bus, stdio_serial) = Self::setup_io_bus()?;
// Create a list of mmio devices to be added.
let mmio_devs = virtio_devs(&mem, &exit_evt)?;
Self::add_arch_devs(&mut vm, &mut mmio_bus)?; Self::add_arch_devs(&mut vm, &mut mmio_bus)?;
for stub in mmio_devs {
arch::register_mmio(&mut mmio_bus, &mut vm, stub.dev, stub.jail,
&mut resources, &mut cmdline)
.map_err(Error::RegisterVsock)?;
}
mmio_bus.insert(pci_bus.clone(), AARCH64_PCI_CFG_BASE, AARCH64_PCI_CFG_SIZE, false) mmio_bus.insert(pci_bus.clone(), AARCH64_PCI_CFG_BASE, AARCH64_PCI_CFG_SIZE, false)
.map_err(Error::RegisterPci)?; .map_err(Error::RegisterPci)?;

View file

@ -29,7 +29,6 @@ pub type Result<T> = result::Result<T, Box<std::error::Error>>;
/// Holds the pieces needed to build a VM. Passed to `build_vm` in the `LinuxArch` trait below to /// Holds the pieces needed to build a VM. Passed to `build_vm` in the `LinuxArch` trait below to
/// create a `RunnableLinuxVm`. /// create a `RunnableLinuxVm`.
pub struct VmComponents { pub struct VmComponents {
pub pci_devices: Vec<(Box<PciDevice + 'static>, Minijail)>,
pub memory_mb: u64, pub memory_mb: u64,
pub vcpu_count: u32, pub vcpu_count: u32,
pub kernel_image: File, pub kernel_image: File,
@ -67,7 +66,7 @@ pub trait LinuxArch {
/// * `virtio_devs` - Function to generate a list of virtio devices. /// * `virtio_devs` - Function to generate a list of virtio devices.
fn build_vm<F>(components: VmComponents, virtio_devs: F) -> Result<RunnableLinuxVm> fn build_vm<F>(components: VmComponents, virtio_devs: F) -> Result<RunnableLinuxVm>
where where
F: FnOnce(&GuestMemory, &EventFd) -> Result<Vec<VirtioDeviceStub>>; F: FnOnce(&GuestMemory, &EventFd) -> Result<Vec<(Box<PciDevice + 'static>, Minijail)>>;
} }
/// Errors for device manager. /// Errors for device manager.

View file

@ -25,7 +25,7 @@ use rand::thread_rng;
use rand::distributions::{IndependentSample, Range}; use rand::distributions::{IndependentSample, Range};
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use devices::{self, PciDevice}; use devices::{self, PciDevice, VirtioPciDevice};
use io_jail::{self, Minijail}; use io_jail::{self, Minijail};
use kvm::*; use kvm::*;
use net_util::Tap; use net_util::Tap;
@ -92,6 +92,7 @@ pub enum Error {
TimerFd(sys_util::Error), TimerFd(sys_util::Error),
VhostNetDeviceNew(devices::virtio::vhost::Error), VhostNetDeviceNew(devices::virtio::vhost::Error),
VhostVsockDeviceNew(devices::virtio::vhost::Error), VhostVsockDeviceNew(devices::virtio::vhost::Error),
VirtioPciDev(sys_util::Error),
WaylandDeviceNew(sys_util::Error), WaylandDeviceNew(sys_util::Error),
LoadKernel(Box<error::Error>), LoadKernel(Box<error::Error>),
} }
@ -167,6 +168,7 @@ impl fmt::Display for Error {
&Error::VhostVsockDeviceNew(ref e) => { &Error::VhostVsockDeviceNew(ref e) => {
write!(f, "failed to set up virtual socket device: {:?}", e) write!(f, "failed to set up virtual socket device: {:?}", e)
} }
&Error::VirtioPciDev(ref e) => write!(f, "failed to create virtio pci dev: {}", e),
&Error::WaylandDeviceNew(ref e) => { &Error::WaylandDeviceNew(ref e) => {
write!(f, "failed to create wayland device: {:?}", e) write!(f, "failed to create wayland device: {:?}", e)
} }
@ -234,12 +236,13 @@ fn create_base_minijail(root: &Path, seccomp_policy: &Path) -> Result<Minijail>
Ok(j) Ok(j)
} }
fn create_virtio_devs(cfg: VirtIoDeviceInfo, fn create_virtio_devs(
mem: &GuestMemory, cfg: VirtIoDeviceInfo,
_exit_evt: &EventFd, mem: &GuestMemory,
wayland_device_socket: UnixDatagram, _exit_evt: &EventFd,
balloon_device_socket: UnixDatagram) wayland_device_socket: UnixDatagram,
-> std::result::Result<Vec<VirtioDeviceStub>, Box<error::Error>> { balloon_device_socket: UnixDatagram,
) -> std::result::Result<Vec<(Box<PciDevice + 'static>, Minijail)>, Box<error::Error>> {
static DEFAULT_PIVOT_ROOT: &'static str = "/var/empty"; static DEFAULT_PIVOT_ROOT: &'static str = "/var/empty";
let mut devs = Vec::new(); let mut devs = Vec::new();
@ -578,7 +581,20 @@ fn create_virtio_devs(cfg: VirtIoDeviceInfo,
devs.push(VirtioDeviceStub {dev: p9_box, jail}); devs.push(VirtioDeviceStub {dev: p9_box, jail});
} }
Ok(devs) let mut pci_devices: Vec<(Box<PciDevice + 'static>, Minijail)> = Vec::new();
for stub in devs {
let pci_dev =
Box::new(VirtioPciDevice::new((*mem).clone(), stub.dev).map_err(Error::VirtioPciDev)?);
// TODO(dverkamp): Make this work in non-multiprocess mode without creating an empty jail
let jail = match stub.jail {
Some(j) => j,
None => Minijail::new().unwrap(),
};
pci_devices.push((pci_dev, jail));
}
Ok(pci_devices)
} }
fn setup_vcpu_signal_handler() -> Result<()> { fn setup_vcpu_signal_handler() -> Result<()> {
@ -695,15 +711,12 @@ pub fn run_config(cfg: Config) -> Result<()> {
info!("crosvm entering multiprocess mode"); info!("crosvm entering multiprocess mode");
} }
let pci_devices: Vec<(Box<PciDevice + 'static>, Minijail)> = Vec::new();
// Masking signals is inherently dangerous, since this can persist across clones/execs. Do this // Masking signals is inherently dangerous, since this can persist across clones/execs. Do this
// before any jailed devices have been spawned, so that we can catch any of them that fail very // before any jailed devices have been spawned, so that we can catch any of them that fail very
// quickly. // quickly.
let sigchld_fd = SignalFd::new(libc::SIGCHLD).map_err(Error::CreateSignalFd)?; let sigchld_fd = SignalFd::new(libc::SIGCHLD).map_err(Error::CreateSignalFd)?;
let components = VmComponents { let components = VmComponents {
pci_devices,
memory_mb: (cfg.memory.unwrap_or(256) << 20) as u64, memory_mb: (cfg.memory.unwrap_or(256) << 20) as u64,
vcpu_count: cfg.vcpu_count.unwrap_or(1), vcpu_count: cfg.vcpu_count.unwrap_or(1),
kernel_image: File::open(cfg.kernel_path.as_path()) kernel_image: File::open(cfg.kernel_path.as_path())

View file

@ -8,6 +8,7 @@ build = "build.rs"
arch = { path = "../arch" } arch = { path = "../arch" }
data_model = { path = "../data_model" } data_model = { path = "../data_model" }
devices = { path = "../devices" } devices = { path = "../devices" }
io_jail = { path = "../io_jail" }
kvm_sys = { path = "../kvm_sys" } kvm_sys = { path = "../kvm_sys" }
kvm = { path = "../kvm" } kvm = { path = "../kvm" }
sys_util = { path = "../sys_util" } sys_util = { path = "../sys_util" }

View file

@ -6,6 +6,7 @@ extern crate arch;
extern crate byteorder; extern crate byteorder;
extern crate data_model; extern crate data_model;
extern crate devices; extern crate devices;
extern crate io_jail;
extern crate kvm; extern crate kvm;
extern crate kvm_sys; extern crate kvm_sys;
extern crate libc; extern crate libc;
@ -67,10 +68,11 @@ use std::ffi::{CStr, CString};
use std::io::{self, stdout}; use std::io::{self, stdout};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use arch::{RunnableLinuxVm, VirtioDeviceStub, VmComponents}; use arch::{RunnableLinuxVm, VmComponents};
use bootparam::boot_params; use bootparam::boot_params;
use bootparam::E820_RAM; use bootparam::E820_RAM;
use devices::{PciConfigIo, PciInterruptPin}; use devices::{PciConfigIo, PciDevice, PciInterruptPin};
use io_jail::Minijail;
use sys_util::{EventFd, GuestAddress, GuestMemory}; use sys_util::{EventFd, GuestAddress, GuestMemory};
use resources::{AddressRanges, SystemAllocator}; use resources::{AddressRanges, SystemAllocator};
use kvm::*; use kvm::*;
@ -252,7 +254,7 @@ fn arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)> {
impl arch::LinuxArch for X8664arch { impl arch::LinuxArch for X8664arch {
fn build_vm<F>(mut components: VmComponents, virtio_devs: F) -> Result<RunnableLinuxVm> fn build_vm<F>(mut components: VmComponents, virtio_devs: F) -> Result<RunnableLinuxVm>
where where
F: FnOnce(&GuestMemory, &EventFd) -> Result<Vec<VirtioDeviceStub>> F: FnOnce(&GuestMemory, &EventFd) -> Result<Vec<(Box<PciDevice + 'static>, Minijail)>>
{ {
let mut resources = Self::get_resource_allocator(components.memory_mb, let mut resources = Self::get_resource_allocator(components.memory_mb,
components.wayland_dmabuf); components.wayland_dmabuf);
@ -275,29 +277,21 @@ impl arch::LinuxArch for X8664arch {
let mut mmio_bus = devices::Bus::new(); let mut mmio_bus = devices::Bus::new();
let (pci, pci_irqs) = arch::generate_pci_root(components.pci_devices, let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?;
let pci_devices = virtio_devs(&mem, &exit_evt)?;
let (pci, pci_irqs) = arch::generate_pci_root(pci_devices,
&mut mmio_bus, &mut mmio_bus,
&mut resources, &mut resources,
&mut vm) &mut vm)
.map_err(Error::CreatePciRoot)?; .map_err(Error::CreatePciRoot)?;
let pci_bus = Arc::new(Mutex::new(PciConfigIo::new(pci))); let pci_bus = Arc::new(Mutex::new(PciConfigIo::new(pci)));
let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?;
let (io_bus, stdio_serial) = Self::setup_io_bus( let (io_bus, stdio_serial) = Self::setup_io_bus(
&mut vm, &mut vm,
exit_evt.try_clone().map_err(Error::CloneEventFd)?, exit_evt.try_clone().map_err(Error::CloneEventFd)?,
Some(pci_bus.clone()))?; Some(pci_bus.clone()))?;
// Create a list of mmio devices to be added.
let mmio_devs = virtio_devs(&mem, &exit_evt)?;
for stub in mmio_devs {
arch::register_mmio(&mut mmio_bus, &mut vm, stub.dev, stub.jail,
&mut resources, &mut cmdline)
.map_err(Error::RegisterVsock)?;
}
for param in components.extra_kernel_params { for param in components.extra_kernel_params {
cmdline.insert_str(&param).map_err(Error::Cmdline)?; cmdline.insert_str(&param).map_err(Error::Cmdline)?;
} }