pvmfw: Clean pre-populated pvIOMMUs when unused

platform.dts has pre-populated pvIOMMU nodes for device assignment.
The nodes needs to be cleaned even when nothing is assigned.

Bug: 277993056
Test: atest libpvmfw.device_assignment.test, TH
Change-Id: Iac5af3609bcce5bdedcf1abd45c4d07c06415700
diff --git a/pvmfw/src/device_assignment.rs b/pvmfw/src/device_assignment.rs
index 86ad0f0..c732822 100644
--- a/pvmfw/src/device_assignment.rs
+++ b/pvmfw/src/device_assignment.rs
@@ -816,6 +816,18 @@
     }
 }
 
+/// Cleans device trees not to contain any pre-populated nodes/props for device assignment.
+pub fn clean(fdt: &mut Fdt) -> Result<()> {
+    let mut compatible = fdt.root_mut().next_compatible(cstr!("pkvm,pviommu"))?;
+    // Filters pre-populated
+    while let Some(filtered_pviommu) = compatible {
+        compatible = filtered_pviommu.delete_and_next_compatible(cstr!("pkvm,pviommu"))?;
+    }
+
+    // Removes any dangling references in __symbols__ (e.g. removed pvIOMMUs)
+    filter_dangling_symbols(fdt)
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -1378,4 +1390,18 @@
 
         assert_eq!(device_info, Err(DeviceAssignmentError::InvalidIommus));
     }
+
+    #[test]
+    fn device_assignment_clean() {
+        let mut platform_dt_data = pvmfw_fdt_template::RAW.to_vec();
+        let platform_dt = Fdt::from_mut_slice(&mut platform_dt_data).unwrap();
+
+        let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu"));
+        assert_ne!(None, compatible.unwrap());
+
+        clean(platform_dt).unwrap();
+
+        let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu"));
+        assert_eq!(Ok(None), compatible);
+    }
 }
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 51ba112..d847ca2 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -15,7 +15,7 @@
 //! High-level FDT functions.
 
 use crate::bootargs::BootArgsIterator;
-use crate::device_assignment::{DeviceAssignmentInfo, VmDtbo};
+use crate::device_assignment::{self, DeviceAssignmentInfo, VmDtbo};
 use crate::helpers::GUEST_PAGE_SIZE;
 use crate::Box;
 use crate::RebootReason;
@@ -1158,6 +1158,11 @@
             error!("Failed to patch device assignment info to DT: {e}");
             RebootReason::InvalidFdt
         })?;
+    } else {
+        device_assignment::clean(fdt).map_err(|e| {
+            error!("Failed to clean pre-polulated DT nodes for device assignment: {e}");
+            RebootReason::InvalidFdt
+        })?;
     }
     patch_untrusted_props(fdt, &info.untrusted_props).map_err(|e| {
         error!("Failed to patch untrusted properties: {e}");