libavf: implement setHypervisorSpecificAuthMethod for Gunyah

Bug: 381971305
Bug: 380912007
Test: m
Change-Id: Ic997b73f5cad00d4b93a1aff64ee3d24aebf2c6f
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 0cde751..c71b5c5 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -588,8 +588,11 @@
             check_gdb_allowed(config)?;
         }
 
+        let instance_id = extract_instance_id(config);
         let mut device_tree_overlays = vec![];
-        if let Some(dt_overlay) = maybe_create_reference_dt_overlay(config, &temporary_directory)? {
+        if let Some(dt_overlay) =
+            maybe_create_reference_dt_overlay(config, &instance_id, &temporary_directory)?
+        {
             device_tree_overlays.push(dt_overlay);
         }
         if let Some(dtbo) = get_dtbo(config) {
@@ -860,6 +863,8 @@
             balloon: config.balloon,
             usb_config,
             dump_dt_fd,
+            enable_hypervisor_specific_auth_method: config.enableHypervisorSpecificAuthMethod,
+            instance_id,
         };
         let instance = Arc::new(
             VmInstance::new(
@@ -947,6 +952,7 @@
 
 fn maybe_create_reference_dt_overlay(
     config: &VirtualMachineConfig,
+    instance_id: &[u8; 64],
     temporary_directory: &Path,
 ) -> binder::Result<Option<File>> {
     // Currently, VirtMgr adds the host copy of reference DT & untrusted properties
@@ -975,11 +981,9 @@
         vec![]
     };
 
-    let instance_id;
     let key_material;
     let mut untrusted_props = Vec::with_capacity(2);
     if cfg!(llpvm_changes) {
-        instance_id = extract_instance_id(config);
         untrusted_props.push((cstr!("instance-id"), &instance_id[..]));
         let want_updatable = extract_want_updatable(config);
         if want_updatable && is_secretkeeper_supported() {
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index f3b669f..a90c1ff 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -137,6 +137,8 @@
     pub balloon: bool,
     pub usb_config: UsbConfig,
     pub dump_dt_fd: Option<File>,
+    pub enable_hypervisor_specific_auth_method: bool,
+    pub instance_id: [u8; 64],
 }
 
 #[derive(Debug)]
@@ -989,7 +991,29 @@
 
     let mut memory_mib = config.memory_mib;
 
+    if config.enable_hypervisor_specific_auth_method && !config.protected {
+        bail!("hypervisor specific auth method only supported for protected VMs");
+    }
     if config.protected {
+        if config.enable_hypervisor_specific_auth_method {
+            if !hypervisor_props::is_gunyah()? {
+                bail!("hypervisor specific auth method not supported for current hypervisor");
+            }
+            // "QCOM Trusted VM" compatibility mode.
+            //
+            // When this mode is enabled, two hypervisor specific IDs are expected to be packed
+            // into the instance ID. We extract them here and pass along to crosvm so they can be
+            // given to the hypervisor driver via an ioctl.
+            let vm_id = u32::from_le_bytes(config.instance_id[60..64].try_into().unwrap());
+            let pas_id = u16::from_le_bytes(config.instance_id[58..60].try_into().unwrap());
+            command.arg("--hypervisor").arg(
+                format!("gunyah[device=/dev/gunyah,qcom_trusted_vm_id={vm_id},qcom_trusted_vm_pas_id={pas_id}]"),
+            );
+            // Put the FDT close to the payload (default is end of RAM) to so that CMA can be used
+            // without bloating memory usage.
+            command.arg("--fdt-position").arg("after-payload");
+        }
+
         match system_properties::read(SYSPROP_CUSTOM_PVMFW_PATH)? {
             Some(pvmfw_path) if !pvmfw_path.is_empty() => {
                 if pvmfw_path == "none" {
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index 62a6d57..b6eff64 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -120,4 +120,10 @@
 
     /** List of tee services this VM wants to access */
     String[] teeServices;
+
+    /**
+     * Set whether to use an alternate, hypervisor-specific authentication method for protected
+     * VMs.
+     */
+    boolean enableHypervisorSpecificAuthMethod;
 }
diff --git a/libs/hypervisor_props/src/lib.rs b/libs/hypervisor_props/src/lib.rs
index 14614fd..094e895 100644
--- a/libs/hypervisor_props/src/lib.rs
+++ b/libs/hypervisor_props/src/lib.rs
@@ -37,3 +37,8 @@
 pub fn version() -> Result<Option<String>> {
     Ok(hypervisorproperties::hypervisor_version()?)
 }
+
+/// Returns if the hypervisor is Gunyah
+pub fn is_gunyah() -> Result<bool> {
+    Ok(version()?.unwrap_or_default().starts_with("gunyah"))
+}
diff --git a/libs/libavf/src/lib.rs b/libs/libavf/src/lib.rs
index 4f23da4..6532ace 100644
--- a/libs/libavf/src/lib.rs
+++ b/libs/libavf/src/lib.rs
@@ -237,16 +237,21 @@
     config.protectedVm = protected_vm;
 }
 
-/// NOT IMPLEMENTED.
+/// Set whether to use an alternate, hypervisor-specific authentication method for protected VMs.
 ///
-/// # Returns
-/// It always returns `-ENOTSUP`.
+/// # Safety
+/// `config` must be a pointer returned by `AVirtualMachineRawConfig_create`.
 #[no_mangle]
-pub extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
-    _config: *mut VirtualMachineRawConfig,
-    _enable: bool,
+pub unsafe extern "C" fn AVirtualMachineRawConfig_setHypervisorSpecificAuthMethod(
+    config: *mut VirtualMachineRawConfig,
+    enable: bool,
 ) -> c_int {
-    -libc::ENOTSUP
+    // SAFETY: `config` is assumed to be a valid, non-null pointer returned by
+    // AVirtualMachineRawConfig_create. It's the only reference to the object.
+    let config = unsafe { &mut *config };
+    config.enableHypervisorSpecificAuthMethod = enable;
+    // We don't validate whether this is supported until later, when the VM is started.
+    0
 }
 
 /// NOT IMPLEMENTED.