From 39a6990cb7a37f56ceceba23d875d496dc637fac Mon Sep 17 00:00:00 2001 From: Chao Wu Date: Thu, 9 Feb 2023 15:08:05 +0800 Subject: [PATCH] TDX: add confidential_vm_type for TDX add confidential_vm_type to let Dragonball create a TDX VM. fixes: #6246 Signed-off-by: fengshifang Signed-off-by: Chao Wu --- src/dragonball/src/api/v1/instance_info.rs | 15 ++++++- src/dragonball/src/api/v1/mod.rs | 2 +- src/dragonball/src/error.rs | 4 ++ src/dragonball/src/kvm_context.rs | 47 +++++++++++++++++----- src/dragonball/src/vm/mod.rs | 21 +++++++++- 5 files changed, 77 insertions(+), 12 deletions(-) diff --git a/src/dragonball/src/api/v1/instance_info.rs b/src/dragonball/src/api/v1/instance_info.rs index 86174a2fd7..9d89c488f3 100644 --- a/src/dragonball/src/api/v1/instance_info.rs +++ b/src/dragonball/src/api/v1/instance_info.rs @@ -5,6 +5,15 @@ use serde_derive::{Deserialize, Serialize}; +/// This struct represents the strongly typed equivalent of the json body +/// from confidential container related requests. +#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub enum ConfidentialVmType { + /// Intel Trusted Domain + TDX = 2, +} + /// The microvm state. /// /// When Dragonball starts, the instance state is Uninitialized. Once start_microvm method is @@ -56,10 +65,12 @@ pub struct InstanceInfo { pub tids: Vec<(u8, u32)>, /// Last instance downtime pub last_instance_downtime: u64, + /// confidential vm type + pub confidential_vm_type: Option, } impl InstanceInfo { - /// create instance info object with given id, version, and platform type + /// create instance info object with given id, version, platform type and confidential vm type. pub fn new(id: String, vmm_version: String) -> Self { InstanceInfo { id, @@ -69,6 +80,7 @@ impl InstanceInfo { async_state: AsyncState::Uninitialized, tids: Vec::new(), last_instance_downtime: 0, + confidential_vm_type: None, } } } @@ -83,6 +95,7 @@ impl Default for InstanceInfo { async_state: AsyncState::Uninitialized, tids: Vec::new(), last_instance_downtime: 0, + confidential_vm_type: None, } } } diff --git a/src/dragonball/src/api/v1/mod.rs b/src/dragonball/src/api/v1/mod.rs index 99e3075ebb..8ca00b6f75 100644 --- a/src/dragonball/src/api/v1/mod.rs +++ b/src/dragonball/src/api/v1/mod.rs @@ -12,7 +12,7 @@ pub use self::boot_source::{BootSourceConfig, BootSourceConfigError, DEFAULT_KER /// Wrapper over the microVM general information. mod instance_info; -pub use self::instance_info::{InstanceInfo, InstanceState}; +pub use self::instance_info::{ConfidentialVmType, InstanceInfo, InstanceState}; /// Wrapper for configuring the memory and CPU of the microVM. mod machine_config; diff --git a/src/dragonball/src/error.rs b/src/dragonball/src/error.rs index 9ad0b07923..7677ebd19b 100644 --- a/src/dragonball/src/error.rs +++ b/src/dragonball/src/error.rs @@ -68,6 +68,10 @@ pub enum Error { /// Cannot open the VM file descriptor. #[error(transparent)] Vm(vm::VmError), + + /// confidential vm type Error + #[error("confidential-vm-type can only be used in x86_64 now")] + ConfidentialVmType, } /// Errors associated with starting the instance. diff --git a/src/dragonball/src/kvm_context.rs b/src/dragonball/src/kvm_context.rs index ce45834588..72f330842a 100644 --- a/src/dragonball/src/kvm_context.rs +++ b/src/dragonball/src/kvm_context.rs @@ -10,7 +10,7 @@ use kvm_bindings::KVM_API_VERSION; use kvm_ioctls::{Cap, Kvm, VmFd}; use std::os::unix::io::{FromRawFd, RawFd}; -use crate::error::{Error, Result}; +use crate::error::{Error as VmError, Result}; /// Describes a KVM context that gets attached to the micro VM instance. /// It gives access to the functionality of the KVM wrapper as long as every required @@ -29,11 +29,11 @@ impl KvmContext { // Safe because we expect kvm_fd to contain a valid fd number when is_some() == true. unsafe { Kvm::from_raw_fd(fd) } } else { - Kvm::new().map_err(Error::Kvm)? + Kvm::new().map_err(VmError::Kvm)? }; if kvm.get_api_version() != KVM_API_VERSION as i32 { - return Err(Error::KvmApiVersion(kvm.get_api_version())); + return Err(VmError::KvmApiVersion(kvm.get_api_version())); } Self::check_cap(&kvm, Cap::Irqchip)?; @@ -44,7 +44,8 @@ impl KvmContext { Self::check_cap(&kvm, Cap::SetTssAddr)?; #[cfg(target_arch = "x86_64")] - let supported_msrs = dbs_arch::msr::supported_guest_msrs(&kvm).map_err(Error::GuestMSRs)?; + let supported_msrs = + dbs_arch::msr::supported_guest_msrs(&kvm).map_err(VmError::GuestMSRs)?; let max_memslots = kvm.get_nr_memslots(); Ok(KvmContext { @@ -67,7 +68,7 @@ impl KvmContext { /// Create a virtual machine object. pub fn create_vm(&self) -> Result { - self.kvm.create_vm().map_err(Error::Kvm) + self.kvm.create_vm().map_err(VmError::Kvm) } /// Get the max vcpu count supported by kvm @@ -75,9 +76,9 @@ impl KvmContext { self.kvm.get_max_vcpus() } - fn check_cap(kvm: &Kvm, cap: Cap) -> std::result::Result<(), Error> { + fn check_cap(kvm: &Kvm, cap: Cap) -> std::result::Result<(), VmError> { if !kvm.check_extension(cap) { - return Err(Error::KvmCap(cap)); + return Err(VmError::KvmCap(cap)); } Ok(()) } @@ -91,6 +92,18 @@ mod x86_64 { use std::collections::HashSet; impl KvmContext { + /// Create a virtual machine object with specific type. + /// vm_type: u64 + /// 0: legacy vm + /// 2: tdx vm + pub fn create_vm_with_type(&self, vm_type: u64) -> Result { + let fd = self + .kvm + .create_vm_with_type(vm_type) + .map_err(VmError::Kvm)?; + Ok(fd) + } + /// Get information about supported CPUID of x86 processor. pub fn supported_cpuid( &self, @@ -110,7 +123,7 @@ mod x86_64 { // It's very sensible to manipulate MSRs, so please be careful to change code below. fn build_msrs_list(kvm: &Kvm) -> Result { let mut mset: HashSet = HashSet::new(); - let supported_msr_list = kvm.get_msr_index_list().map_err(super::Error::Kvm)?; + let supported_msr_list = kvm.get_msr_index_list().map_err(VmError::Kvm)?; for msr in supported_msr_list.as_slice() { mset.insert(*msr); } @@ -203,7 +216,7 @@ mod x86_64 { }) .collect(); - Msrs::from_entries(&msrs).map_err(super::Error::Msr) + Msrs::from_entries(&msrs).map_err(VmError::Msr) } } } @@ -257,4 +270,20 @@ mod tests { let _ = c.create_vm().unwrap(); } + + #[test] + fn test_create_vm_with_type() { + let c = KvmContext::new(None).unwrap(); + #[cfg(not(target_arch = "aarch64"))] + let _ = c.create_vm_with_type(0_u64).unwrap(); + #[cfg(target_arch = "aarch64")] + { + /// aarch64 is using ipa_size to create vm + let mut ipa_size = 0; // Create using default VM type + if c.check_extension(kvm_ioctls::Cap::ArmVmIPASize) { + ipa_size = c.kvm.get_host_ipa_limit(); + } + let _ = c.create_vm_with_type(ipa_size as u64).unwrap(); + } + } } diff --git a/src/dragonball/src/vm/mod.rs b/src/dragonball/src/vm/mod.rs index 8ad959c791..51262c92fd 100644 --- a/src/dragonball/src/vm/mod.rs +++ b/src/dragonball/src/vm/mod.rs @@ -203,7 +203,26 @@ impl Vm { let id = api_shared_info.read().unwrap().id.clone(); let logger = slog_scope::logger().new(slog::o!("id" => id)); let kvm = KvmContext::new(kvm_fd)?; - let vm_fd = Arc::new(kvm.create_vm()?); + let vm_fd = match api_shared_info + .as_ref() + .read() + .unwrap() + .confidential_vm_type + { + None => Arc::new(kvm.create_vm()?), + Some(confidential_vm_type) => { + #[cfg(not(any(target_arch = "x86_64")))] + { + error!( + "confidential-vm-type {} only can be used in x86_64", + confidential_vm_type as u64 + ); + return Err(Error::ConfidentialVmType); + } + #[cfg(target_arch = "x86_64")] + Arc::new(kvm.create_vm_with_type(confidential_vm_type as u64)?) + } + }; let resource_manager = Arc::new(ResourceManager::new(Some(kvm.max_memslots()))); let device_manager = DeviceManager::new( vm_fd.clone(),