diff options
-rw-r--r-- | hypervisor/src/kvm/aarch64.rs | 18 | ||||
-rw-r--r-- | hypervisor/src/kvm/mod.rs | 12 | ||||
-rw-r--r-- | hypervisor/src/kvm/x86_64.rs | 116 | ||||
-rw-r--r-- | hypervisor/src/lib.rs | 18 |
4 files changed, 132 insertions, 32 deletions
diff --git a/hypervisor/src/kvm/aarch64.rs b/hypervisor/src/kvm/aarch64.rs index 4f0398f..4e5b65c 100644 --- a/hypervisor/src/kvm/aarch64.rs +++ b/hypervisor/src/kvm/aarch64.rs @@ -2,10 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -use sys_util::Result; +use libc::ENXIO; + +use sys_util::{Error, Result}; use super::{KvmVcpu, KvmVm}; -use crate::{VcpuAArch64, VmAArch64}; +use crate::{ClockState, VcpuAArch64, VmAArch64}; + +impl KvmVm { + /// Arch-specific implementation of `Vm::get_pvclock`. Always returns an error on AArch64. + pub fn get_pvclock_arch(&self) -> Result<ClockState> { + Err(Error::new(ENXIO)) + } + + /// Arch-specific implementation of `Vm::set_pvclock`. Always returns an error on AArch64. + pub fn set_pvclock_arch(&self, _state: &ClockState) -> Result<()> { + Err(Error::new(ENXIO)) + } +} impl VmAArch64 for KvmVm { type Vcpu = KvmVcpu; diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 0550792..5fdf124 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -24,7 +24,9 @@ use sys_util::{ GuestMemory, RawDescriptor, Result, SafeDescriptor, }; -use crate::{Hypervisor, HypervisorCap, MappedRegion, RunnableVcpu, Vcpu, VcpuExit, Vm}; +use crate::{ + ClockState, Hypervisor, HypervisorCap, MappedRegion, RunnableVcpu, Vcpu, VcpuExit, Vm, +}; // Wrapper around KVM_SET_USER_MEMORY_REGION ioctl, which creates, modifies, or deletes a mapping // from guest physical to host user pages. @@ -184,6 +186,14 @@ impl Vm for KvmVm { fn get_memory(&self) -> &GuestMemory { &self.guest_mem } + + fn get_pvclock(&self) -> Result<ClockState> { + self.get_pvclock_arch() + } + + fn set_pvclock(&self, state: &ClockState) -> Result<()> { + self.set_pvclock_arch(state) + } } impl AsRawDescriptor for KvmVm { diff --git a/hypervisor/src/kvm/x86_64.rs b/hypervisor/src/kvm/x86_64.rs index 06774f4..f3fbc59 100644 --- a/hypervisor/src/kvm/x86_64.rs +++ b/hypervisor/src/kvm/x86_64.rs @@ -4,14 +4,17 @@ use std::convert::TryInto; -use kvm_sys::*; use libc::E2BIG; -use sys_util::{ioctl_with_mut_ptr, Error, Result}; + +use kvm_sys::*; +use sys_util::{ + errno_result, ioctl_with_mut_ptr, ioctl_with_mut_ref, ioctl_with_ref, Error, Result, +}; use super::{Kvm, KvmVcpu, KvmVm}; use crate::{ - CpuId, CpuIdEntry, HypervisorX86_64, IoapicRedirectionTableEntry, IoapicState, LapicState, - PicState, PitChannelState, PitState, Regs, VcpuX86_64, VmX86_64, + ClockState, CpuId, CpuIdEntry, HypervisorX86_64, IoapicRedirectionTableEntry, IoapicState, + LapicState, PicState, PitChannelState, PitState, Regs, VcpuX86_64, VmX86_64, }; type KvmCpuId = kvm::CpuId; @@ -54,6 +57,58 @@ impl Kvm { } } +impl HypervisorX86_64 for Kvm { + fn get_supported_cpuid(&self) -> Result<CpuId> { + self.get_cpuid(KVM_GET_SUPPORTED_CPUID()) + } + + fn get_emulated_cpuid(&self) -> Result<CpuId> { + self.get_cpuid(KVM_GET_EMULATED_CPUID()) + } +} + +impl KvmVm { + /// Arch-specific implementation of `Vm::get_pvclock`. + pub fn get_pvclock_arch(&self) -> Result<ClockState> { + // Safe because we know that our file is a VM fd, we know the kernel will only write correct + // amount of memory to our pointer, and we verify the return result. + let mut clock_data: kvm_clock_data = unsafe { std::mem::zeroed() }; + let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_CLOCK(), &mut clock_data) }; + if ret == 0 { + Ok(ClockState::from(clock_data)) + } else { + errno_result() + } + } + + /// Arch-specific implementation of `Vm::set_pvclock`. + pub fn set_pvclock_arch(&self, state: &ClockState) -> Result<()> { + let clock_data = kvm_clock_data::from(*state); + // Safe because we know that our file is a VM fd, we know the kernel will only read correct + // amount of memory from our pointer, and we verify the return result. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_CLOCK(), &clock_data) }; + if ret == 0 { + Ok(()) + } else { + errno_result() + } + } +} + +impl VmX86_64 for KvmVm { + type Vcpu = KvmVcpu; + + fn create_vcpu(&self, id: usize) -> Result<Self::Vcpu> { + self.create_kvm_vcpu(id) + } +} + +impl VcpuX86_64 for KvmVcpu { + fn get_regs(&self) -> Result<Regs> { + Ok(Regs {}) + } +} + impl<'a> From<&'a KvmCpuId> for CpuId { fn from(kvm_cpuid: &'a KvmCpuId) -> CpuId { let kvm_entries = kvm_cpuid.entries_slice(); @@ -74,27 +129,22 @@ impl<'a> From<&'a KvmCpuId> for CpuId { } } -impl HypervisorX86_64 for Kvm { - fn get_supported_cpuid(&self) -> Result<CpuId> { - self.get_cpuid(KVM_GET_SUPPORTED_CPUID()) - } - - fn get_emulated_cpuid(&self) -> Result<CpuId> { - self.get_cpuid(KVM_GET_EMULATED_CPUID()) - } -} - -impl VmX86_64 for KvmVm { - type Vcpu = KvmVcpu; - - fn create_vcpu(&self, id: usize) -> Result<Self::Vcpu> { - self.create_kvm_vcpu(id) +impl From<ClockState> for kvm_clock_data { + fn from(state: ClockState) -> Self { + kvm_clock_data { + clock: state.clock, + flags: state.flags, + ..Default::default() + } } } -impl VcpuX86_64 for KvmVcpu { - fn get_regs(&self) -> Result<Regs> { - Ok(Regs {}) +impl From<kvm_clock_data> for ClockState { + fn from(clock_data: kvm_clock_data) -> Self { + ClockState { + clock: clock_data.clock, + flags: clock_data.flags, + } } } @@ -305,15 +355,13 @@ impl From<&kvm_pit_channel_state> for PitChannelState { #[cfg(test)] mod tests { + use super::*; use crate::{ - DeliveryMode, DeliveryStatus, DestinationMode, IoapicRedirectionTableEntry, IoapicState, - LapicState, PicInitState, PicState, PitChannelState, PitRWMode, PitRWState, PitState, - TriggerMode, + DeliveryMode, DeliveryStatus, DestinationMode, HypervisorX86_64, + IoapicRedirectionTableEntry, IoapicState, LapicState, PicInitState, PicState, + PitChannelState, PitRWMode, PitRWState, PitState, TriggerMode, Vm, }; - use kvm_sys::*; - - use super::Kvm; - use crate::HypervisorX86_64; + use sys_util::{GuestAddress, GuestMemory}; #[test] fn get_supported_cpuid() { @@ -501,4 +549,14 @@ mod tests { // convert back and compare assert_eq!(state, PitState::from(&kvm_state)); } + + #[test] + fn clock_handling() { + let kvm = Kvm::new().unwrap(); + let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap(); + let vm = KvmVm::new(&kvm, gm).unwrap(); + let mut clock_data = vm.get_pvclock().unwrap(); + clock_data.clock += 1000; + vm.set_pvclock(&clock_data).unwrap(); + } } diff --git a/hypervisor/src/lib.rs b/hypervisor/src/lib.rs index 784af8c..ee0bcaf 100644 --- a/hypervisor/src/lib.rs +++ b/hypervisor/src/lib.rs @@ -33,6 +33,14 @@ pub trait Vm: Send + Sized { /// Gets the guest-mapped memory for the Vm. fn get_memory(&self) -> &GuestMemory; + + /// Retrieves the current timestamp of the paravirtual clock as seen by the current guest. + /// Only works on VMs that support `VmCap::PvClock`. + fn get_pvclock(&self) -> Result<ClockState>; + + /// Sets the current timestamp of the paravirtual clock as seen by the current guest. + /// Only works on VMs that support `VmCap::PvClock`. + fn set_pvclock(&self, state: &ClockState) -> Result<()>; } /// A wrapper around using a VCPU. @@ -83,4 +91,14 @@ pub enum VcpuExit { Unknown, } +/// A single route for an IRQ. pub struct IrqRoute {} + +/// The state of the paravirtual clock +#[derive(Debug, Default, Copy, Clone)] +pub struct ClockState { + /// Current pv clock timestamp, as seen by the guest + pub clock: u64, + /// Hypervisor-specific feature flags for the pv clock + pub flags: u32, +} |