mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-30 04:19:20 +00:00
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:
parent
a158e31038
commit
d635acbaf3
7 changed files with 47 additions and 42 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
35
src/linux.rs
35
src/linux.rs
|
@ -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())
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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(¶m).map_err(Error::Cmdline)?;
|
cmdline.insert_str(¶m).map_err(Error::Cmdline)?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue