diff --git a/Cargo.lock b/Cargo.lock index f139c53b3..b80a6d939 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -461,6 +461,7 @@ dependencies = [ "kvm-ioctls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "linux-loader 0.1.0 (git+https://github.com/bjzhjing/linux-loader)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "net_util 0.1.0", "pci 0.1.0", "qcow 0.1.0", diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 0e23c57c6..bcc38f38d 100755 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -11,6 +11,7 @@ epoll = "=4.0.1" kvm-bindings = "0.1" kvm-ioctls = "0.1.0" libc = ">=0.2.39" +log = "*" net_util = { path = "../net_util" } pci = {path = "../pci"} qcow = { path = "../qcow" } diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 5fa3e9660..51a26c501 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -4,6 +4,8 @@ // extern crate kvm_ioctls; +#[macro_use] +extern crate log; use kvm_ioctls::*; use std::fmt::{self, Display}; diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index cfa421e77..256d0b5e4 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -141,6 +141,9 @@ pub enum Error { /// Failed parsing network parameters ParseNetworkParameters, + + /// Unexpected KVM_RUN exit reason + VcpuUnhandledKvmExit, } pub type Result = result::Result; @@ -195,6 +198,8 @@ pub type DeviceManagerResult = result::Result; pub struct Vcpu { fd: VcpuFd, id: u8, + io_bus: devices::Bus, + mmio_bus: devices::Bus, } impl Vcpu { @@ -204,10 +209,15 @@ impl Vcpu { /// /// * `id` - Represents the CPU number between [0, max vcpus). /// * `vm` - The virtual machine this vcpu will get attached to. - pub fn new(id: u8, vm: &Vm) -> Result { + pub fn new(id: u8, vm: &Vm, io_bus: devices::Bus, mmio_bus: devices::Bus) -> Result { let kvm_vcpu = vm.fd.create_vcpu(id).map_err(Error::VcpuFd)?; // Initially the cpuid per vCPU is the one supported by this VM. - Ok(Vcpu { fd: kvm_vcpu, id }) + Ok(Vcpu { + fd: kvm_vcpu, + id, + io_bus, + mmio_bus, + }) } /// Configures a x86_64 specific vcpu and should be called once per vcpu from the vcpu's thread. @@ -242,8 +252,39 @@ impl Vcpu { /// /// Note that the state of the VCPU and associated VM must be setup first for this to do /// anything useful. - pub fn run(&self) -> Result { - self.fd.run().map_err(Error::VcpuRun) + pub fn run(&self) -> Result<()> { + match self.fd.run() { + Ok(run) => match run { + VcpuExit::IoIn(addr, data) => { + self.io_bus.read(u64::from(addr), data); + Ok(()) + } + VcpuExit::IoOut(addr, data) => { + self.io_bus.write(u64::from(addr), data); + Ok(()) + } + VcpuExit::MmioRead(addr, data) => { + self.mmio_bus.read(addr as u64, data); + Ok(()) + } + VcpuExit::MmioWrite(addr, data) => { + self.mmio_bus.write(addr as u64, data); + Ok(()) + } + r => { + error!("Unexpected exit reason on vcpu run: {:?}", r); + Err(Error::VcpuUnhandledKvmExit) + } + }, + + Err(ref e) => match e.raw_os_error().unwrap() { + libc::EAGAIN | libc::EINTR => Ok(()), + _ => { + error!("VCPU {:?} error {:?}", self.id, e); + Err(Error::VcpuUnhandledKvmExit) + } + }, + } } } @@ -782,10 +823,9 @@ impl<'a> Vm<'a> { let vcpu_thread_barrier = Arc::new(Barrier::new((vcpu_count + 1) as usize)); for cpu_id in 0..vcpu_count { - println!("Starting VCPU {:?}", cpu_id); let io_bus = self.devices.io_bus.clone(); let mmio_bus = self.devices.mmio_bus.clone(); - let mut vcpu = Vcpu::new(cpu_id, &self)?; + let mut vcpu = Vcpu::new(cpu_id, &self, io_bus, mmio_bus)?; vcpu.configure(entry_addr, &self)?; let vcpu_thread_barrier = vcpu_thread_barrier.clone(); @@ -810,67 +850,7 @@ impl<'a> Vm<'a> { // Block until all CPUs are ready. vcpu_thread_barrier.wait(); - loop { - match vcpu.run() { - Ok(run) => match run { - VcpuExit::IoIn(addr, data) => { - io_bus.read(u64::from(addr), data); - } - VcpuExit::IoOut(addr, data) => { - io_bus.write(u64::from(addr), data); - } - VcpuExit::MmioRead(addr, data) => { - mmio_bus.read(addr as u64, data); - } - VcpuExit::MmioWrite(addr, data) => { - mmio_bus.write(addr as u64, data); - } - VcpuExit::Unknown => { - println!("Unknown"); - } - VcpuExit::Exception => { - println!("Exception"); - } - VcpuExit::Hypercall => {} - VcpuExit::Debug => {} - VcpuExit::Hlt => { - println!("HLT"); - } - VcpuExit::IrqWindowOpen => {} - VcpuExit::Shutdown => {} - VcpuExit::FailEntry => {} - VcpuExit::Intr => {} - VcpuExit::SetTpr => {} - VcpuExit::TprAccess => {} - VcpuExit::S390Sieic => {} - VcpuExit::S390Reset => {} - VcpuExit::Dcr => {} - VcpuExit::Nmi => {} - VcpuExit::InternalError => {} - VcpuExit::Osi => {} - VcpuExit::PaprHcall => {} - VcpuExit::S390Ucontrol => {} - VcpuExit::Watchdog => {} - VcpuExit::S390Tsch => {} - VcpuExit::Epr => {} - VcpuExit::SystemEvent => {} - VcpuExit::S390Stsi => {} - VcpuExit::IoapicEoi => {} - VcpuExit::Hyperv => {} - }, - Err(Error::VcpuRun(ref e)) => { - match e.raw_os_error().unwrap() { - // Why do we check for these if we only return EINVAL? - libc::EAGAIN | libc::EINTR => {} - _ => { - println! {"VCPU {:?} error {:?}", cpu_id, e}; - break; - } - } - } - _ => (), - } - } + while vcpu.run().is_ok() {} }) .map_err(Error::VcpuSpawn)?, );