Merge changes I2e8a8f64,I72769fab into main * changes: crosvm: gunyah: Support launching QTVMs hypervisor: gunyah: Add balloon support
diff --git a/crosvm_control/src/lib.rs b/crosvm_control/src/lib.rs index 6c58382..c68f5fc 100644 --- a/crosvm_control/src/lib.rs +++ b/crosvm_control/src/lib.rs
@@ -30,7 +30,9 @@ use balloon_control::BalloonStats; use balloon_control::BalloonWS; use balloon_control::WSBucket; +use base::descriptor::IntoRawDescriptor; use libc::c_char; +use libc::c_int; use libc::ssize_t; pub use swap::SwapStatus; use vm_control::client::do_modify_battery; @@ -47,6 +49,7 @@ use vm_control::BalloonControlCommand; use vm_control::BatProperty; use vm_control::DiskControlCommand; +use vm_control::HypervisorKind; use vm_control::RegisteredEvent; use vm_control::SwapCommand; use vm_control::UsbControlAttachedDevice; @@ -1305,3 +1308,78 @@ }) .unwrap_or(false) } + +/// Publicly exposed version enumeration of hypervisors, implemented as an +/// integral newtype for FFI safety. +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct HypervisorFfi(u32); + +pub const HYPERVISOR_KVM: HypervisorFfi = HypervisorFfi(0); + +impl TryFrom<&HypervisorKind> for HypervisorFfi { + type Error = &'static str; + + fn try_from(hypervisor: &HypervisorKind) -> Result<Self, Self::Error> { + match hypervisor { + HypervisorKind::Kvm => Ok(HYPERVISOR_KVM), + _ => Err("unsupported hypervisor"), + } + } +} + +/// Hypervisor specific unique identifier of a VM. +#[repr(C)] +pub union HypervisorSpecificVmDescriptorFfi { + // We use c_int instead of RawFd here because the std::os::fd crate is only available on unix + // platforms. + vm_fd: c_int, + _reserved: u64, +} + +/// A unique identifier of a VM. +#[repr(C)] +pub struct VmDescriptorFfi { + hypervisor: HypervisorFfi, + descriptor: HypervisorSpecificVmDescriptorFfi, +} + +/// Get a descriptor representing a running VM. +/// +/// The function returns true on success or false if an error occurred. +/// +/// # Safety +/// Function is unsafe due to raw pointer usage - a null pointer could be passed in. Usage of +/// !raw_pointer.is_null() checks should prevent unsafe behavior but the caller should ensure no +/// null pointers are passed. +#[no_mangle] +pub unsafe extern "C" fn crosvm_get_vm_descriptor( + socket_path: *const c_char, + vm_desc_out: *mut VmDescriptorFfi, +) -> bool { + catch_unwind(|| { + let Some(socket_path) = validate_socket_path(socket_path) else { + return false; + }; + + if vm_desc_out.is_null() { + return false; + } + + let resp = handle_request(&VmRequest::GetVmDescriptor, socket_path); + if let Ok(VmResponse::VmDescriptor { hypervisor, vm_fd }) = resp { + let Ok(hypervisor) = HypervisorFfi::try_from(&hypervisor) else { + return false; + }; + // SAFETY: just checked that `vm_desc_out` is not null. + (*vm_desc_out).hypervisor = hypervisor; + // On windows platforms RawDescriptor is actually a *mut c_void, hence cast to c_int + // here. + (*vm_desc_out).descriptor.vm_fd = vm_fd.into_raw_descriptor() as c_int; + true + } else { + false + } + }) + .unwrap_or(false) +}
diff --git a/hypervisor/src/geniezone/mod.rs b/hypervisor/src/geniezone/mod.rs index cab457f..7b4900f 100644 --- a/hypervisor/src/geniezone/mod.rs +++ b/hypervisor/src/geniezone/mod.rs
@@ -62,6 +62,7 @@ use crate::DeviceKind; use crate::Hypervisor; use crate::HypervisorCap; +use crate::HypervisorKind; use crate::IoEventAddress; use crate::IoOperation; use crate::IoParams; @@ -883,6 +884,15 @@ }) } + fn try_clone_descriptor(&self) -> Result<SafeDescriptor> { + error!("try_clone_descriptor hasn't been tested on geniezone, returning -ENOTSUP"); + Err(Error::new(ENOTSUP)) + } + + fn hypervisor_kind(&self) -> HypervisorKind { + HypervisorKind::Geniezone + } + fn check_capability(&self, c: VmCap) -> bool { if let Some(val) = self.check_capability_arch(c) { return val;
diff --git a/hypervisor/src/gunyah/mod.rs b/hypervisor/src/gunyah/mod.rs index 5a772ba..2ab6c39 100644 --- a/hypervisor/src/gunyah/mod.rs +++ b/hypervisor/src/gunyah/mod.rs
@@ -21,6 +21,7 @@ use anyhow::Context; use base::errno_result; +use base::error; use base::info; use base::ioctl; use base::ioctl_with_ref; @@ -557,6 +558,15 @@ }) } + fn try_clone_descriptor(&self) -> Result<SafeDescriptor> { + error!("try_clone_descriptor hasn't been tested on gunyah, returning -ENOTSUP"); + Err(Error::new(ENOTSUP)) + } + + fn hypervisor_kind(&self) -> HypervisorKind { + HypervisorKind::Gunyah + } + fn check_capability(&self, c: VmCap) -> bool { match c { VmCap::DirtyLog => false,
diff --git a/hypervisor/src/haxm/vm.rs b/hypervisor/src/haxm/vm.rs index 8876d18..ddb4dd7 100644 --- a/hypervisor/src/haxm/vm.rs +++ b/hypervisor/src/haxm/vm.rs
@@ -44,6 +44,7 @@ use crate::Datamatch; use crate::DeviceKind; use crate::Hypervisor; +use crate::HypervisorKind; use crate::IoEventAddress; use crate::MemCacheType; use crate::MemSlot; @@ -225,6 +226,14 @@ }) } + fn try_clone_descriptor(&self) -> Result<SafeDescriptor> { + Err(Error::new(ENOTSUP)) + } + + fn hypervisor_kind(&self) -> HypervisorKind { + HypervisorKind::Haxm + } + fn check_capability(&self, c: VmCap) -> bool { match c { VmCap::DirtyLog => false,
diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 14da211..90ab682 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs
@@ -74,6 +74,7 @@ use crate::DeviceKind; use crate::Hypervisor; use crate::HypervisorCap; +use crate::HypervisorKind; use crate::IoEventAddress; use crate::IoOperation; use crate::IoParams; @@ -587,6 +588,14 @@ }) } + fn try_clone_descriptor(&self) -> Result<SafeDescriptor> { + self.vm.try_clone() + } + + fn hypervisor_kind(&self) -> HypervisorKind { + HypervisorKind::Kvm + } + fn check_capability(&self, c: VmCap) -> bool { if let Some(val) = self.check_capability_arch(c) { return val;
diff --git a/hypervisor/src/lib.rs b/hypervisor/src/lib.rs index 8abc20b..fa50892 100644 --- a/hypervisor/src/lib.rs +++ b/hypervisor/src/lib.rs
@@ -95,6 +95,18 @@ BalloonTargetReached(u64), } +/// Supported hypervisors. +/// +/// When adding a new one, also update the HypervisorFfi in crosvm_control/src/lib.rs +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum HypervisorKind { + Geniezone, + Gunyah, + Kvm, + Haxm, + Whpx, +} + /// A trait for checking hypervisor capabilities. pub trait Hypervisor: Send { /// Makes a shallow clone of this `Hypervisor`. @@ -113,6 +125,12 @@ where Self: Sized; + /// Makes a shallow clone of the fd of this `Vm`. + fn try_clone_descriptor(&self) -> Result<SafeDescriptor>; + + /// Returns hypervisor managing this `Vm`. + fn hypervisor_kind(&self) -> HypervisorKind; + /// Checks if a particular `VmCap` is available. /// /// This is distinct from the `Hypervisor` version of this method because some extensions depend
diff --git a/hypervisor/src/whpx/vm.rs b/hypervisor/src/whpx/vm.rs index 2aae1c4..26a0d34 100644 --- a/hypervisor/src/whpx/vm.rs +++ b/hypervisor/src/whpx/vm.rs
@@ -52,6 +52,7 @@ use crate::DeliveryMode; use crate::DestinationMode; use crate::DeviceKind; +use crate::HypervisorKind; use crate::IoEventAddress; use crate::LapicState; use crate::MemCacheType; @@ -498,6 +499,14 @@ }) } + fn try_clone_descriptor(&self) -> Result<SafeDescriptor> { + Err(Error::new(ENOTSUP)) + } + + fn hypervisor_kind(&self) -> HypervisorKind { + HypervisorKind::Whpx + } + fn check_capability(&self, c: VmCap) -> bool { match c { VmCap::DirtyLog => Whpx::check_whpx_feature(WhpxFeature::DirtyPageTracking)
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs index e6575cc..42e9f72 100644 --- a/vm_control/src/lib.rs +++ b/vm_control/src/lib.rs
@@ -1516,6 +1516,8 @@ VcpuPidTid, /// Throttles the requested vCPU for microseconds Throttle(usize, u32), + /// Returns unique descriptor of this VM. + GetVmDescriptor, } /// NOTE: when making any changes to this enum please also update @@ -2248,6 +2250,19 @@ VmRequest::Unregister { socket_addr: _ } => VmResponse::Ok, VmRequest::VcpuPidTid => unreachable!(), VmRequest::Throttle(_, _) => unreachable!(), + VmRequest::GetVmDescriptor => { + let vm_fd = match vm.try_clone_descriptor() { + Ok(vm_fd) => vm_fd, + Err(e) => { + error!("failed to get vm_fd: {:?}", e); + return VmResponse::Err(e); + } + }; + VmResponse::VmDescriptor { + hypervisor: vm.hypervisor_kind(), + vm_fd, + } + } } } } @@ -2473,6 +2488,8 @@ Ok(()) } +pub type HypervisorKind = hypervisor::HypervisorKind; + /// Indication of success or failure of a `VmRequest`. /// /// Success is usually indicated `VmResponse::Ok` unless there is data associated with the response. @@ -2517,6 +2534,10 @@ VcpuPidTidResponse { pid_tid_map: BTreeMap<usize, (u32, u32)>, }, + VmDescriptor { + hypervisor: HypervisorKind, + vm_fd: SafeDescriptor, + }, } impl Display for VmResponse { @@ -2567,6 +2588,9 @@ } DevicesState(status) => write!(f, "devices status: {:?}", status), VcpuPidTidResponse { pid_tid_map } => write!(f, "vcpu pid tid map: {:?}", pid_tid_map), + VmDescriptor { hypervisor, vm_fd } => { + write!(f, "hypervisor: {:?}, vm_fd: {:?}", hypervisor, vm_fd) + } } } }