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)
+            }
         }
     }
 }