diff --git a/Cargo.lock b/Cargo.lock index 257ccff98..9d9233ef6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -457,6 +457,19 @@ dependencies = [ [[package]] name = "hypervisor" version = "0.1.0" +dependencies = [ + "anyhow", + "kvm-bindings", + "kvm-ioctls", + "libc", + "linux-loader", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "vm-memory", + "vmm-sys-util", +] [[package]] name = "idna" diff --git a/hypervisor/Cargo.toml b/hypervisor/Cargo.toml index 42424cc15..317845dfb 100644 --- a/hypervisor/Cargo.toml +++ b/hypervisor/Cargo.toml @@ -5,4 +5,18 @@ authors = ["Muminul Islam"] edition = "2018" -[dependencies] \ No newline at end of file +[dependencies] +anyhow = "1.0" +thiserror = "1.0" +libc = "0.2.69" +kvm-ioctls = { git = "https://github.com/cloud-hypervisor/kvm-ioctls", branch = "ch" } +kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch", features = ["with-serde", "fam-wrappers"] } +serde = {version = ">=1.0.27", features = ["rc"] } +serde_derive = ">=1.0.27" +serde_json = ">=1.0.9" +vm-memory = { version = "0.2.0", features = ["backend-mmap", "backend-atomic"] } +vmm-sys-util = { version = ">=0.5.0", features = ["with-serde"] } + +[dependencies.linux-loader] +git = "https://github.com/rust-vmm/linux-loader" +features = ["elf", "bzimage"] diff --git a/hypervisor/src/cpu.rs b/hypervisor/src/cpu.rs new file mode 100644 index 000000000..a72e9d95a --- /dev/null +++ b/hypervisor/src/cpu.rs @@ -0,0 +1,273 @@ +// Copyright © 2019 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2020, Microsoft Corporation +// +// Copyright 2018-2019 CrowdStrike, Inc. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +#[cfg(target_arch = "aarch64")] +use crate::aarch64::VcpuInit; +#[cfg(target_arch = "x86_64")] +pub use crate::x86_64::{CpuId, ExtendedControlRegisters, LapicState, MsrEntries, Xsave}; +use crate::{FpuState, MpState, SpecialRegisters, StandardRegisters, VcpuEvents, VcpuExit}; +use thiserror::Error; +use vmm_sys_util::errno::Error as RunError; + +pub struct CpuState {} + +#[derive(Error, Debug)] +/// +/// Enum for CPU error +pub enum HypervisorCpuError { + /// + /// Setting standard registers error + /// + #[error("Failed to set standard register: {0}")] + SetStandardRegs(#[source] anyhow::Error), + /// + /// Setting standard registers error + /// + #[error("Failed to get standard registers: {0}")] + GetStandardRegs(#[source] anyhow::Error), + /// + /// Setting special register error + /// + #[error("Failed to set special registers: {0}")] + SetSpecialRegs(#[source] anyhow::Error), + /// + /// Getting standard register error + /// + #[error("Failed to get special registers: {0}")] + GetSpecialRegs(#[source] anyhow::Error), + /// + /// Setting floating point registers error + /// + #[error("Failed to set special register: {0}")] + SetFloatingPointRegs(#[source] anyhow::Error), + /// + /// Getting floating point register error + /// + #[error("Failed to get special register: {0}")] + GetFloatingPointRegs(#[source] anyhow::Error), + /// + /// Setting Cpuid error + /// + #[error("Failed to set Cpuid: {0}")] + SetCpuid(#[source] anyhow::Error), + /// + /// Getting Cpuid error + /// + #[error("Failed to get Cpuid: {0}")] + GetCpuid(#[source] anyhow::Error), + /// + /// Setting lapic state error + /// + #[error("Failed to set Lapic state: {0}")] + SetLapicState(#[source] anyhow::Error), + /// + /// Getting Lapic state error + /// + #[error("Failed to get Lapic state: {0}")] + GetlapicState(#[source] anyhow::Error), + /// + /// Setting MSR entries error + /// + #[error("Failed to set Msr entries: {0}")] + SetMsrEntries(#[source] anyhow::Error), + /// + /// Getting Msr entries error + /// + #[error("Failed to get Msr entries: {0}")] + GetMsrEntries(#[source] anyhow::Error), + /// + /// Setting MSR entries error + /// + #[error("Failed to set MP state: {0}")] + SetMpState(#[source] anyhow::Error), + /// + /// Getting Msr entries error + /// + #[error("Failed to get MP state: {0}")] + GetMpState(#[source] anyhow::Error), + /// + /// Setting Saved Processor Extended States error + /// + #[error("Failed to set Saved Processor Extended States: {0}")] + SetXsaveState(#[source] anyhow::Error), + /// + /// Getting Saved Processor Extended States error + /// + #[error("Failed to get Saved Processor Extended States: {0}")] + GetXsaveState(#[source] anyhow::Error), + /// + /// Setting Extended Control Registers error + /// + #[error("Failed to set Extended Control Registers: {0}")] + SetXcsr(#[source] anyhow::Error), + /// + /// Getting Extended Control Registers error + /// + #[error("Failed to get Extended Control Registers: {0}")] + GetXcsr(#[source] anyhow::Error), + /// + /// Running Vcpu error + /// + #[error("Failed to run vcpu: {0}")] + RunVcpu(#[source] anyhow::Error), + /// + /// Getting Vcpu events error + /// + #[error("Failed to get Vcpu events: {0}")] + GetVcpuEvents(#[source] anyhow::Error), + /// + /// Vcpu Init error + /// + #[error("Failed to init vcpu: {0}")] + VcpuInit(#[source] anyhow::Error), + /// + /// Setting one reg error + /// + #[error("Failed to init vcpu: {0}")] + SetOneReg(#[source] anyhow::Error), + /// + /// Getting one reg error + /// + #[error("Failed to init vcpu: {0}")] + GetOneReg(#[source] anyhow::Error), +} + +/// +/// Result type for returning from a function +/// +pub type Result = anyhow::Result; +/// +/// Trait to represent a generic Vcpu +/// +pub trait Vcpu: Send + Sync { + #[cfg(target_arch = "x86_64")] + /// + /// Returns the vCPU general purpose registers. + /// + fn get_regs(&self) -> Result; + + #[cfg(target_arch = "x86_64")] + /// + /// Sets the vCPU general purpose registers. + /// + fn set_regs(&self, regs: &StandardRegisters) -> Result<()>; + #[cfg(target_arch = "x86_64")] + /// + /// Returns the vCPU special registers. + /// + fn get_sregs(&self) -> Result; + #[cfg(target_arch = "x86_64")] + /// + /// Sets the vCPU special registers + /// + fn set_sregs(&self, sregs: &SpecialRegisters) -> Result<()>; + #[cfg(target_arch = "x86_64")] + /// + /// Returns the floating point state (FPU) from the vCPU. + /// + fn get_fpu(&self) -> Result; + #[cfg(target_arch = "x86_64")] + /// + /// Set the floating point state (FPU) of a vCPU + /// + fn set_fpu(&self, fpu: &FpuState) -> Result<()>; + #[cfg(target_arch = "x86_64")] + /// + /// X86 specific call to setup the CPUID registers. + /// + fn set_cpuid2(&self, cpuid: &CpuId) -> Result<()>; + #[cfg(target_arch = "x86_64")] + /// + /// X86 specific call to retrieve the CPUID registers. + /// + fn get_cpuid2(&self, num_entries: usize) -> Result; + #[cfg(target_arch = "x86_64")] + /// + /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller). + /// + fn get_lapic(&self) -> Result; + #[cfg(target_arch = "x86_64")] + /// + /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller). + /// + fn set_lapic(&self, lapic: &LapicState) -> Result<()>; + #[cfg(target_arch = "x86_64")] + /// + /// Returns the model-specific registers (MSR) for this vCPU. + /// + fn get_msrs(&self, msrs: &mut MsrEntries) -> Result; + #[cfg(target_arch = "x86_64")] + /// + /// Setup the model-specific registers (MSR) for this vCPU. + /// + fn set_msrs(&self, msrs: &MsrEntries) -> Result; + /// + /// Returns the vcpu's current "multiprocessing state". + /// + fn get_mp_state(&self) -> Result; + /// + /// Sets the vcpu's current "multiprocessing state". + /// + fn set_mp_state(&self, mp_state: MpState) -> Result<()>; + #[cfg(target_arch = "x86_64")] + /// + /// X86 specific call that returns the vcpu's current "xsave struct". + /// + fn get_xsave(&self) -> Result; + #[cfg(target_arch = "x86_64")] + /// + /// X86 specific call that sets the vcpu's current "xsave struct". + /// + fn set_xsave(&self, xsave: &Xsave) -> Result<()>; + #[cfg(target_arch = "x86_64")] + /// + /// X86 specific call that returns the vcpu's current "xcrs". + /// + fn get_xcrs(&self) -> Result; + #[cfg(target_arch = "x86_64")] + /// + /// X86 specific call that sets the vcpu's current "xcrs". + /// + fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> Result<()>; + /// + /// Triggers the running of the current virtual CPU returning an exit reason. + /// + fn run(&self) -> std::result::Result; + #[cfg(target_arch = "x86_64")] + /// + /// Returns currently pending exceptions, interrupts, and NMIs as well as related + /// states of the vcpu. + /// + fn get_vcpu_events(&self) -> Result; + /// + /// Sets the type of CPU to be exposed to the guest and optional features. + /// + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + fn vcpu_init(&self, kvi: &VcpuInit) -> Result<()>; + /// + /// Sets the value of one register for this vCPU. + /// + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + fn set_one_reg(&self, reg_id: u64, data: u64) -> Result<()>; + /// + /// Sets the value of one register for this vCPU. + /// + #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + fn get_one_reg(&self, reg_id: u64) -> Result; + /// + /// Retrieve the current cpu states. This function is necessary to snapshot the VM + /// + fn cpu_state(&self) -> Result; + /// + /// Setting the FPU state this. + /// This function is required when restoring the VM + /// + fn set_cpu_state(&self, state: &CpuState) -> Result<()>; +} diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs new file mode 100644 index 000000000..cda2c3f02 --- /dev/null +++ b/hypervisor/src/kvm/mod.rs @@ -0,0 +1,24 @@ +// Copyright © 2019 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2020, Microsoft Corporation +// +// Copyright 2018-2019 CrowdStrike, Inc. +// +// + +#[cfg(target_arch = "x86_64")] +pub mod x86_64; + +#[cfg(target_arch = "x86_64")] +pub use x86_64::{CpuId, ExtendedControlRegisters, LapicState, MsrEntries, Xsave}; + +/// +/// Export generically-named wrappers of kvm-bindings for Unix-based platforms +/// +pub use { + kvm_bindings::kvm_fpu as FpuState, kvm_bindings::kvm_mp_state as MpState, + kvm_bindings::kvm_regs as StandardRegisters, kvm_bindings::kvm_sregs as SpecialRegisters, + kvm_bindings::kvm_vcpu_events as VcpuEvents, kvm_ioctls::VcpuExit, +}; diff --git a/hypervisor/src/kvm/x86_64/mod.rs b/hypervisor/src/kvm/x86_64/mod.rs new file mode 100644 index 000000000..eea3ac73b --- /dev/null +++ b/hypervisor/src/kvm/x86_64/mod.rs @@ -0,0 +1,18 @@ +// Copyright © 2019 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2020, Microsoft Corporation +// +// Copyright 2018-2019 CrowdStrike, Inc. +// +// + +/// +/// Export generically-named wrappers of kvm-bindings for Unix-based platforms +/// +pub use { + kvm_bindings::kvm_lapic_state as LapicState, + kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave as Xsave, + kvm_bindings::CpuId, kvm_bindings::Msrs as MsrEntries, +}; diff --git a/hypervisor/src/lib.rs b/hypervisor/src/lib.rs index 2b8f852d4..ccb84d6dc 100644 --- a/hypervisor/src/lib.rs +++ b/hypervisor/src/lib.rs @@ -6,3 +6,23 @@ // // Copyright 2018-2019 CrowdStrike, Inc. // +// + +//! A generic abstraction around hypervisor functionality +//! +//! This crate offers a trait abstraction for underlying hypervisors +//! +//! # Platform support +//! +//! - x86_64 +//! - arm64 +//! + +/// KVM implementation module +pub mod kvm; + +/// CPU related module +mod cpu; + +pub use cpu::{HypervisorCpuError, Vcpu}; +pub use kvm::*;