summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/device_manager.rs81
-rw-r--r--src/linux.rs151
2 files changed, 114 insertions, 118 deletions
diff --git a/src/device_manager.rs b/src/device_manager.rs
index 284f3e1..4c02da0 100644
--- a/src/device_manager.rs
+++ b/src/device_manager.rs
@@ -5,38 +5,28 @@
 //! Manages jailing and connecting virtio devices to the system bus.
 
 use std::fmt;
-use std::io;
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::sync::{Arc, Mutex};
 
 use libc::STDERR_FILENO;
 
 use io_jail::Minijail;
-use kvm::IoeventAddress;
+use kvm::{Vm, IoeventAddress};
 use sys_util::{GuestMemory, syslog};
 use sys_util;
 
 use devices;
 use kernel_cmdline;
-use vm_control::VmRequest;
 
 /// Errors for device manager.
 #[derive(Debug)]
 pub enum Error {
     /// Could not create the mmio device to wrap a VirtioDevice.
     CreateMmioDevice(sys_util::Error),
-    /// Failed to clone a queue's ioeventfd.
-    CloneIoeventFd(sys_util::Error),
-    /// Failed to clone the mmio irqfd.
-    CloneIrqFd(sys_util::Error),
-    /// There was an error creating a sync EventFd.
-    CreateSync(sys_util::Error),
-    /// There was an error writing the uid_map.
-    WriteUidMap(io::Error),
-    /// There was an error writing the gid_map.
-    WriteGidMap(io::Error),
-    /// There was an error synchronizing the child process.
-    Sync(sys_util::Error),
+    /// Failed to register ioevent with VM.
+    RegisterIoevent(sys_util::Error),
+    /// Failed to register irq eventfd with VM.
+    RegisterIrqfd(sys_util::Error),
     /// Failed to initialize proxy device for jailed device.
     ProxyDeviceCreation(devices::ProxyError),
     /// Appending to kernel command line failed.
@@ -49,19 +39,17 @@ impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             &Error::CreateMmioDevice(ref e) => write!(f, "failed to create mmio device: {:?}", e),
-            &Error::CloneIoeventFd(ref e) => write!(f, "failed to clone ioeventfd: {:?}", e),
-            &Error::CloneIrqFd(ref e) => write!(f, "failed to clone irqfd: {:?}", e),
-            &Error::CreateSync(ref e) => write!(f, "failed to create sync eventfd: {:?}", e),
-            &Error::WriteUidMap(ref e) => write!(f, "failed to write uid map: {}", e),
-            &Error::WriteGidMap(ref e) => write!(f, "failed to write gid map: {}", e),
-            &Error::Sync(ref e) => write!(f, "failed to sync proxy device start: {:?}", e),
+            &Error::RegisterIoevent(ref e) => {
+                write!(f, "failed to register ioevent to VM: {:?}", e)
+            }
+            &Error::RegisterIrqfd(ref e) => {
+                write!(f, "failed to register irq eventfd to VM: {:?}", e)
+            }
             &Error::ProxyDeviceCreation(ref e) => write!(f, "failed to create proxy device: {}", e),
             &Error::Cmdline(ref e) => {
                 write!(f, "unable to add device to kernel command line: {}", e)
             }
-            &Error::IrqsExhausted => {
-                write!(f, "no more IRQs are available")
-            }
+            &Error::IrqsExhausted => write!(f, "no more IRQs are available"),
         }
     }
 }
@@ -71,25 +59,30 @@ type Result<T> = ::std::result::Result<T, Error>;
 const MAX_IRQ: u32 = 15;
 
 /// Manages the complexities of adding a device.
-pub struct DeviceManager {
+pub struct DeviceManager<'a> {
     pub bus: devices::Bus,
-    pub vm_requests: Vec<VmRequest>,
+    vm: &'a mut Vm,
     guest_mem: GuestMemory,
     mmio_len: u64,
     mmio_base: u64,
     irq: u32,
 }
 
-impl DeviceManager {
+impl<'a> DeviceManager<'a> {
     /// Create a new DeviceManager.
-    pub fn new(guest_mem: GuestMemory, mmio_len: u64, mmio_base: u64, irq_base: u32) -> DeviceManager {
+    pub fn new(vm: &mut Vm,
+               guest_mem: GuestMemory,
+               mmio_len: u64,
+               mmio_base: u64,
+               irq_base: u32)
+               -> DeviceManager {
         DeviceManager {
-            guest_mem: guest_mem,
-            vm_requests: Vec::new(),
-            mmio_len: mmio_len,
-            mmio_base: mmio_base,
-            irq: irq_base,
             bus: devices::Bus::new(),
+            vm,
+            guest_mem,
+            mmio_len,
+            mmio_base,
+            irq: irq_base,
         }
     }
 
@@ -113,25 +106,22 @@ impl DeviceManager {
         for (i, queue_evt) in mmio_device.queue_evts().iter().enumerate() {
             let io_addr = IoeventAddress::Mmio(self.mmio_base +
                                                devices::virtio::NOITFY_REG_OFFSET as u64);
-            self.vm_requests.push(VmRequest::RegisterIoevent(queue_evt
-                                                                 .try_clone()
-                                                                 .map_err(Error::CloneIoeventFd)?,
-                                                             io_addr,
-                                                             i as u32));
+            self.vm
+                .register_ioevent(&queue_evt, io_addr, i as u32)
+                .map_err(Error::RegisterIoevent)?;
             keep_fds.push(queue_evt.as_raw_fd());
         }
 
         if let Some(interrupt_evt) = mmio_device.interrupt_evt() {
-            self.vm_requests.push(VmRequest::RegisterIrqfd(interrupt_evt
-                                                               .try_clone()
-                                                               .map_err(Error::CloneIrqFd)?,
-                                                           self.irq));
+            self.vm
+                .register_irqfd(&interrupt_evt, self.irq)
+                .map_err(Error::RegisterIrqfd)?;
             keep_fds.push(interrupt_evt.as_raw_fd());
         }
 
         if let Some(jail) = jail {
             let proxy_dev = devices::ProxyDevice::new(mmio_device, &jail, keep_fds)
-                .map_err(|e| Error::ProxyDeviceCreation(e))?;
+                .map_err(Error::ProxyDeviceCreation)?;
 
             self.bus
                 .insert(Arc::new(Mutex::new(proxy_dev)),
@@ -163,6 +153,7 @@ mod tests {
     use std::sync::atomic::AtomicUsize;
     use std::os::unix::io::RawFd;
     use sys_util::{EventFd, GuestAddress, GuestMemory};
+    use kvm::*;
     use device_manager;
     use kernel_cmdline;
     use devices;
@@ -199,13 +190,15 @@ mod tests {
     }
 
     #[test]
+    #[ignore] // no access to /dev/kvm
     fn register_device() {
         let start_addr1 = GuestAddress(0x0);
         let start_addr2 = GuestAddress(0x1000);
         let guest_mem = GuestMemory::new(&vec![(start_addr1, 0x1000), (start_addr2, 0x1000)])
             .unwrap();
+        let mut vm = Vm::new(&Kvm::new().unwrap(), guest_mem.clone()).unwrap();
         let mut device_manager =
-            device_manager::DeviceManager::new(guest_mem, 0x1000, 0xd0000000, 5);
+            device_manager::DeviceManager::new(&mut vm, guest_mem, 0x1000, 0xd0000000, 5);
 
         let mut cmdline = kernel_cmdline::Cmdline::new(4096);
         let dummy_box = Box::new(DummyDevice { dummy: 0 });
diff --git a/src/linux.rs b/src/linux.rs
index c5c7001..03e2952 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -25,7 +25,7 @@ use kernel_loader;
 use kvm::*;
 use sys_util::*;
 use sys_util;
-use vm_control::{VmResponse, VmRequest};
+use vm_control::VmRequest;
 
 use Config;
 
@@ -181,40 +181,15 @@ fn create_base_minijail(root: &Path, seccomp_policy: &Path) -> Result<Minijail>
     Ok(j)
 }
 
-pub fn run_config(cfg: Config) -> Result<()> {
+fn setup_mmio_bus(vm: &mut Vm,
+                  guest_mem: &GuestMemory,
+                  cfg: Config,
+                  cmdline: &mut kernel_cmdline::Cmdline,
+                  control_sockets: &mut Vec<UnlinkUnixDatagram>,
+                  balloon_device_socket: UnixDatagram)
+                  -> Result<devices::Bus> {
     static DEFAULT_PIVOT_ROOT: &'static str = "/var/empty";
-
-    if cfg.multiprocess {
-        // Printing something to the syslog before entering minijail so that libc's syslogger has a
-        // chance to open files necessary for its operation, like `/etc/localtime`. After jailing,
-        // access to those files will not be possible.
-        info!("crosvm entering multiprocess mode");
-    }
-
-    let kernel_image = File::open(cfg.kernel_path.as_path())
-        .map_err(|e| Error::OpenKernel(cfg.kernel_path.clone(), e))?;
-
-    let mut control_sockets = Vec::new();
-    if let Some(ref path) = cfg.socket_path {
-        let path = Path::new(path);
-        let control_socket = UnixDatagram::bind(path).map_err(|e| Error::Socket(e))?;
-        control_sockets.push(UnlinkUnixDatagram(control_socket));
-    }
-
-    let mem_size = cfg.memory.unwrap_or(256) << 20;
-    #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-    let arch_mem_regions = vec![(GuestAddress(0), mem_size)];
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-    let arch_mem_regions = x86_64::arch_memory_regions(mem_size);
-    let guest_mem =
-        GuestMemory::new(&arch_mem_regions).expect("new mmap failed");
-
-    let mut cmdline = kernel_cmdline::Cmdline::new(CMDLINE_MAX_SIZE);
-    cmdline
-        .insert_str("console=ttyS0 noacpi reboot=k panic=1 pci=off")
-        .unwrap();
-
-    let mut device_manager = DeviceManager::new(guest_mem.clone(), 0x1000, 0xd0000000, 5);
+    let mut device_manager = DeviceManager::new(vm, guest_mem.clone(), 0x1000, 0xd0000000, 5);
 
     // An empty directory for jailed device's pivot root.
     let empty_root_path = Path::new(DEFAULT_PIVOT_ROOT);
@@ -239,8 +214,9 @@ pub fn run_config(cfg: Config) -> Result<()> {
             None
         };
 
-        device_manager.register_mmio(block_box, jail, &mut cmdline)
-                .map_err(Error::RegisterBlock)?;
+        device_manager
+            .register_mmio(block_box, jail, cmdline)
+            .map_err(Error::RegisterBlock)?;
     }
 
     let rng_box = Box::new(devices::virtio::Rng::new().map_err(Error::RngDeviceNew)?);
@@ -250,10 +226,10 @@ pub fn run_config(cfg: Config) -> Result<()> {
     } else {
         None
     };
-    device_manager.register_mmio(rng_box, rng_jail, &mut cmdline)
+    device_manager
+        .register_mmio(rng_box, rng_jail, cmdline)
         .map_err(Error::RegisterRng)?;
 
-    let (balloon_host_socket, balloon_device_socket) = UnixDatagram::pair().map_err(Error::Socket)?;
     let balloon_box = Box::new(devices::virtio::Balloon::new(balloon_device_socket)
                                    .map_err(Error::BalloonDeviceNew)?);
     let balloon_jail = if cfg.multiprocess {
@@ -262,7 +238,7 @@ pub fn run_config(cfg: Config) -> Result<()> {
     } else {
         None
     };
-    device_manager.register_mmio(balloon_box, balloon_jail, &mut cmdline)
+    device_manager.register_mmio(balloon_box, balloon_jail, cmdline)
         .map_err(Error::RegisterBalloon)?;
 
     // We checked above that if the IP is defined, then the netmask is, too.
@@ -289,7 +265,9 @@ pub fn run_config(cfg: Config) -> Result<()> {
                 None
             };
 
-            device_manager.register_mmio(net_box, jail, &mut cmdline).map_err(Error::RegisterNet)?;
+            device_manager
+                .register_mmio(net_box, jail, cmdline)
+                .map_err(Error::RegisterNet)?;
         }
     }
 
@@ -356,7 +334,7 @@ pub fn run_config(cfg: Config) -> Result<()> {
             None
         };
         device_manager
-            .register_mmio(wl_box, jail, &mut cmdline)
+            .register_mmio(wl_box, jail, cmdline)
             .map_err(Error::RegisterWayland)?;
     }
 
@@ -372,7 +350,9 @@ pub fn run_config(cfg: Config) -> Result<()> {
             None
         };
 
-        device_manager.register_mmio(vsock_box, jail, &mut cmdline).map_err(Error::RegisterVsock)?;
+        device_manager
+            .register_mmio(vsock_box, jail, cmdline)
+            .map_err(Error::RegisterVsock)?;
     }
 
     if !cfg.params.is_empty() {
@@ -380,52 +360,75 @@ pub fn run_config(cfg: Config) -> Result<()> {
             .insert_str(cfg.params)
             .map_err(|e| Error::Cmdline(e))?;
     }
+    Ok(device_manager.bus)
+}
+
+pub fn run_config(cfg: Config) -> Result<()> {
+    if cfg.multiprocess {
+        // Printing something to the syslog before entering minijail so that libc's syslogger has a
+        // chance to open files necessary for its operation, like `/etc/localtime`. After jailing,
+        // access to those files will not be possible.
+        info!("crosvm entering multiprocess mode");
+    }
+
+    let kernel_image = File::open(cfg.kernel_path.as_path())
+        .map_err(|e| Error::OpenKernel(cfg.kernel_path.clone(), e))?;
+
+    let mut control_sockets = Vec::new();
+    if let Some(ref path) = cfg.socket_path {
+        let path = Path::new(path);
+        let control_socket = UnixDatagram::bind(path).map_err(|e| Error::Socket(e))?;
+        control_sockets.push(UnlinkUnixDatagram(control_socket));
+    }
 
-    run_kvm(device_manager.vm_requests,
+    let mem_size = cfg.memory.unwrap_or(256) << 20;
+    #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+    let arch_mem_regions = vec![(GuestAddress(0), mem_size)];
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    let arch_mem_regions = x86_64::arch_memory_regions(mem_size);
+    let guest_mem = GuestMemory::new(&arch_mem_regions).expect("new mmap failed");
+
+    let kvm = Kvm::new().map_err(Error::Kvm)?;
+    let mut vm = Vm::new(&kvm, guest_mem.clone()).map_err(Error::Vm)?;
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    {
+        let tss_addr = GuestAddress(0xfffbd000);
+        vm.set_tss_addr(tss_addr).expect("set tss addr failed");
+        vm.create_pit().expect("create pit failed");
+    }
+    vm.create_irq_chip().expect("create irq chip failed");
+
+    let mut cmdline = kernel_cmdline::Cmdline::new(CMDLINE_MAX_SIZE);
+    cmdline
+        .insert_str("console=ttyS0 noacpi reboot=k panic=1 pci=off")
+        .unwrap();
+
+    let vcpu_count = cfg.vcpu_count.unwrap_or(1);
+    let (balloon_host_socket, balloon_device_socket) = UnixDatagram::pair().map_err(Error::Socket)?;
+    let mmio_bus = setup_mmio_bus(&mut vm, &guest_mem, cfg, &mut cmdline, &mut control_sockets, balloon_device_socket)?;
+
+    run_kvm(kvm,
+            vm,
             kernel_image,
             &CString::new(cmdline).unwrap(),
-            cfg.vcpu_count.unwrap_or(1),
-            guest_mem,
-            &device_manager.bus,
+            vcpu_count,
+            mmio_bus,
             control_sockets,
             balloon_host_socket)
 }
 
-fn run_kvm(requests: Vec<VmRequest>,
+fn run_kvm(kvm: Kvm,
+           vm: Vm,
            mut kernel_image: File,
            cmdline: &CStr,
            vcpu_count: u32,
-           guest_mem: GuestMemory,
-           mmio_bus: &devices::Bus,
+           mmio_bus: devices::Bus,
            control_sockets: Vec<UnlinkUnixDatagram>,
            balloon_host_socket: UnixDatagram)
            -> Result<()> {
-    let kvm = Kvm::new().map_err(Error::Kvm)?;
     let kernel_start_addr = GuestAddress(KERNEL_START_OFFSET);
     let cmdline_addr = GuestAddress(CMDLINE_OFFSET);
 
-    let mut vm = Vm::new(&kvm, guest_mem).map_err(Error::Vm)?;
-    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-    {
-        let tss_addr = GuestAddress(0xfffbd000);
-        vm.set_tss_addr(tss_addr).expect("set tss addr failed");
-        vm.create_pit().expect("create pit failed");
-    }
-    vm.create_irq_chip().expect("create irq chip failed");
-
-    let mut next_dev_pfn = BASE_DEV_MEMORY_PFN;
-    for request in requests {
-        let mut running = false;
-        if let VmResponse::Err(e) = request.execute(&mut vm, &mut next_dev_pfn,
-                                                    &mut running, &balloon_host_socket) {
-            return Err(Error::Vm(e));
-        }
-        if !running {
-            info!("configuration requested exit");
-            return Ok(());
-        }
-    }
-
     kernel_loader::load_kernel(vm.get_memory(), kernel_start_addr, &mut kernel_image)?;
     kernel_loader::load_cmdline(vm.get_memory(), cmdline_addr, cmdline)?;
     #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
@@ -571,7 +574,6 @@ fn run_kvm(requests: Vec<VmRequest>,
 
     run_control(vm,
                 control_sockets,
-                next_dev_pfn,
                 stdio_serial,
                 exit_evt,
                 sigchld_fd,
@@ -582,7 +584,6 @@ fn run_kvm(requests: Vec<VmRequest>,
 
 fn run_control(mut vm: Vm,
                control_sockets: Vec<UnlinkUnixDatagram>,
-               mut next_dev_pfn: u64,
                stdio_serial: Arc<Mutex<devices::Serial>>,
                exit_evt: EventFd,
                sigchld_fd: SignalFd,
@@ -597,6 +598,8 @@ fn run_control(mut vm: Vm,
     const CHILD_SIGNAL: u32 = 2;
     const VM_BASE: u32 = 3;
 
+    let mut next_dev_pfn = BASE_DEV_MEMORY_PFN;
+
     let stdin_handle = stdin();
     let stdin_lock = stdin_handle.lock();
     stdin_lock