Merge "platform.dts: Add PLACEHOLDER_CPU_MAP_CLUSTER" into main
diff --git a/pvmfw/src/device_assignment.rs b/pvmfw/src/device_assignment.rs
index 885cd22..f826167 100644
--- a/pvmfw/src/device_assignment.rs
+++ b/pvmfw/src/device_assignment.rs
@@ -28,6 +28,8 @@
 use core::iter::Iterator;
 use core::mem;
 use core::ops::Range;
+// TODO(ptosi): Remove the need for this workaround.
+#[cfg(not(test))]
 use hyp::DeviceAssigningHypervisor;
 use libfdt::{Fdt, FdtError, FdtNode, FdtNodeMut, Phandle, Reg};
 use log::error;
@@ -936,6 +938,18 @@
         Ok(())
     }
 
+    // TODO(b/308694211): Remove this workaround for visibility once using
+    // vmbase::hyp::DeviceAssigningHypervisor for tests.
+    #[cfg(test)]
+    fn parse(
+        fdt: &Fdt,
+        vm_dtbo: &VmDtbo,
+        hypervisor: &dyn DeviceAssigningHypervisor,
+    ) -> Result<Option<Self>> {
+        Self::internal_parse(fdt, vm_dtbo, hypervisor)
+    }
+
+    #[cfg(not(test))]
     /// Parses fdt and vm_dtbo, and creates new DeviceAssignmentInfo
     // TODO(b/277993056): Parse __local_fixups__
     // TODO(b/277993056): Parse __fixups__
@@ -944,6 +958,14 @@
         vm_dtbo: &VmDtbo,
         hypervisor: &dyn DeviceAssigningHypervisor,
     ) -> Result<Option<Self>> {
+        Self::internal_parse(fdt, vm_dtbo, hypervisor)
+    }
+
+    fn internal_parse(
+        fdt: &Fdt,
+        vm_dtbo: &VmDtbo,
+        hypervisor: &dyn DeviceAssigningHypervisor,
+    ) -> Result<Option<Self>> {
         let Some(symbols_node) = vm_dtbo.as_ref().symbols()? else {
             // /__symbols__ should contain all assignable devices.
             // If empty, then nothing can be assigned.
@@ -1061,6 +1083,39 @@
 }
 
 #[cfg(test)]
+#[derive(Clone, Copy, Debug)]
+enum MockHypervisorError {
+    FailedGetPhysMmioToken,
+    FailedGetPhysIommuToken,
+}
+
+#[cfg(test)]
+type MockHypervisorResult<T> = core::result::Result<T, MockHypervisorError>;
+
+#[cfg(test)]
+impl fmt::Display for MockHypervisorError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            MockHypervisorError::FailedGetPhysMmioToken => {
+                write!(f, "Failed to get physical MMIO token")
+            }
+            MockHypervisorError::FailedGetPhysIommuToken => {
+                write!(f, "Failed to get physical IOMMU token")
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+trait DeviceAssigningHypervisor {
+    /// Returns MMIO token.
+    fn get_phys_mmio_token(&self, base_ipa: u64, size: u64) -> MockHypervisorResult<u64>;
+
+    /// Returns DMA token as a tuple of (phys_iommu_id, phys_sid).
+    fn get_phys_iommu_token(&self, pviommu_id: u64, vsid: u64) -> MockHypervisorResult<(u64, u64)>;
+}
+
+#[cfg(test)]
 mod tests {
     use super::*;
     use alloc::collections::{BTreeMap, BTreeSet};
@@ -1105,18 +1160,20 @@
     }
 
     impl DeviceAssigningHypervisor for MockHypervisor {
-        fn get_phys_mmio_token(&self, base_ipa: u64, size: u64) -> hyp::Result<u64> {
-            Ok(*self.mmio_tokens.get(&(base_ipa, size)).ok_or(hyp::Error::KvmError(
-                hyp::KvmError::InvalidParameter,
-                0xc6000012, /* VENDOR_HYP_KVM_DEV_REQ_MMIO_FUNC_ID */
-            ))?)
+        fn get_phys_mmio_token(&self, base_ipa: u64, size: u64) -> MockHypervisorResult<u64> {
+            let token = self.mmio_tokens.get(&(base_ipa, size));
+
+            Ok(*token.ok_or(MockHypervisorError::FailedGetPhysMmioToken)?)
         }
 
-        fn get_phys_iommu_token(&self, pviommu_id: u64, vsid: u64) -> hyp::Result<(u64, u64)> {
-            Ok(*self.iommu_tokens.get(&(pviommu_id, vsid)).ok_or(hyp::Error::KvmError(
-                hyp::KvmError::InvalidParameter,
-                0xc6000013, /* VENDOR_HYP_KVM_DEV_REQ_DMA_FUNC_ID */
-            ))?)
+        fn get_phys_iommu_token(
+            &self,
+            pviommu_id: u64,
+            vsid: u64,
+        ) -> MockHypervisorResult<(u64, u64)> {
+            let token = self.iommu_tokens.get(&(pviommu_id, vsid));
+
+            Ok(*token.ok_or(MockHypervisorError::FailedGetPhysIommuToken)?)
         }
     }
 
diff --git a/tests/helper/src/java/com/android/microdroid/test/common/DeviceProperties.java b/tests/helper/src/java/com/android/microdroid/test/common/DeviceProperties.java
index 2ea748b..69527be 100644
--- a/tests/helper/src/java/com/android/microdroid/test/common/DeviceProperties.java
+++ b/tests/helper/src/java/com/android/microdroid/test/common/DeviceProperties.java
@@ -32,6 +32,7 @@
     private static final String KEY_METRICS_TAG = "debug.hypervisor.metrics_tag";
 
     private static final String CUTTLEFISH_DEVICE_PREFIX = "vsoc_";
+    private static final String CUTTLEFISH_ARM64_DEVICE_PREFIX = "vsoc_arm64";
     private static final String USER_BUILD_TYPE = "user";
     private static final String HWASAN_SUFFIX = "_hwasan";
 
@@ -55,6 +56,15 @@
     }
 
     /**
+     * @return whether the device is a cuttlefish device running on 64 bit Arm.
+     */
+    public boolean isCuttlefishArm64() {
+        String vendorDeviceName = getProperty(KEY_VENDOR_DEVICE);
+        return vendorDeviceName != null
+                && vendorDeviceName.startsWith(CUTTLEFISH_ARM64_DEVICE_PREFIX);
+    }
+
+    /**
      * @return whether the build is HWASAN.
      */
     public boolean isHwasan() {
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index d3f6093..6040531 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -75,6 +75,10 @@
         return getDeviceProperties().isCuttlefish();
     }
 
+    private static boolean isCuttlefishArm64() {
+        return getDeviceProperties().isCuttlefishArm64();
+    }
+
     public static boolean isHwasan() {
         return getDeviceProperties().isHwasan();
     }
@@ -222,6 +226,12 @@
         assume().withMessage("Skip on 5.4 kernel. b/218303240")
                 .that(KERNEL_VERSION)
                 .isNotEqualTo("5.4");
+
+        // Cuttlefish on Arm 64 doesn't and cannot support any form of virtualization, so there's
+        // no point running any of these tests.
+        assume().withMessage("Virtualization not supported on Arm64 Cuttlefish. b/341889915")
+                .that(isCuttlefishArm64())
+                .isFalse();
     }
 
     protected void assumeNoUpdatableVmSupport() throws VirtualMachineException {