From f9b51a41b5ae37e69ddc8646da310a17dd0986a6 Mon Sep 17 00:00:00 2001 From: Muminul Islam Date: Wed, 3 Jun 2020 12:23:56 -0700 Subject: [PATCH] hypervisor: Add Vcpu trait This Vcpu trait should be implemented by each underlying hypervisor. Previously created hypervisor object should create the VM based on already selected hypervisor and Vm object should create this vcpu object based on same hyperviosr. Each of this object should be referenced by trait object i.e . Signed-off-by: Muminul Islam Signed-off-by: Samuel Ortiz --- Cargo.lock | 13 ++ hypervisor/Cargo.toml | 16 +- hypervisor/src/cpu.rs | 273 +++++++++++++++++++++++++++++++ hypervisor/src/kvm/mod.rs | 24 +++ hypervisor/src/kvm/x86_64/mod.rs | 18 ++ hypervisor/src/lib.rs | 20 +++ 6 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 hypervisor/src/cpu.rs create mode 100644 hypervisor/src/kvm/mod.rs create mode 100644 hypervisor/src/kvm/x86_64/mod.rs 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::*;