pvmfw: Clean up dangling references in __symbols__
Bug: 277993056
Test: atest libpvmfw.device_assignment.test
Change-Id: I682868d173e516a52d3e5b09dfb11e31a7aad02f
diff --git a/pvmfw/src/device_assignment.rs b/pvmfw/src/device_assignment.rs
index e427710..2c47f9e 100644
--- a/pvmfw/src/device_assignment.rs
+++ b/pvmfw/src/device_assignment.rs
@@ -294,6 +294,26 @@
.map_or(false, |name| name == b"__overlay__")
}
+fn filter_dangling_symbols(fdt: &mut Fdt) -> Result<()> {
+ if let Some(symbols) = fdt.symbols()? {
+ let mut removed = vec![];
+ for prop in symbols.properties()? {
+ let path = CStr::from_bytes_with_nul(prop.value()?)
+ .map_err(|_| DeviceAssignmentError::Internal)?;
+ if fdt.node(path)?.is_none() {
+ let name = prop.name()?;
+ removed.push(CString::from(name));
+ }
+ }
+
+ let mut symbols = fdt.symbols_mut()?.unwrap();
+ for name in removed {
+ symbols.nop_property(&name)?;
+ }
+ }
+ Ok(())
+}
+
impl AsRef<Fdt> for VmDtbo {
fn as_ref(&self) -> &Fdt {
&self.0
@@ -744,7 +764,8 @@
device.patch(fdt, &pviommu_phandles)?;
}
- Ok(())
+ // Removes any dangling references in __symbols__ (e.g. removed pvIOMMUs)
+ filter_dangling_symbols(fdt)
}
}
@@ -1020,6 +1041,39 @@
}
#[test]
+ fn device_info_patch_no_pviommus() {
+ let mut fdt_data = fs::read(FDT_WITHOUT_IOMMUS_FILE_PATH).unwrap();
+ let mut vm_dtbo_data = fs::read(VM_DTBO_FILE_PATH).unwrap();
+ let mut data = vec![0_u8; fdt_data.len() + vm_dtbo_data.len()];
+ let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap();
+ let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
+ let platform_dt = Fdt::create_empty_tree(data.as_mut_slice()).unwrap();
+
+ let hypervisor = MockHypervisor {
+ mmio_tokens: [((0x9, 0xFF), 0x300)].into(),
+ iommu_tokens: BTreeMap::new(),
+ };
+ let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor).unwrap().unwrap();
+ device_info.filter(vm_dtbo).unwrap();
+
+ // SAFETY: Damaged VM DTBO wouldn't be used after this unsafe block.
+ unsafe {
+ platform_dt.apply_overlay(vm_dtbo.as_mut()).unwrap();
+ }
+ device_info.patch(platform_dt).unwrap();
+
+ let compatible = platform_dt.root().next_compatible(cstr!("pkvm,pviommu")).unwrap();
+ assert_eq!(None, compatible);
+
+ if let Some(symbols) = platform_dt.symbols().unwrap() {
+ for prop in symbols.properties().unwrap() {
+ let path = CStr::from_bytes_with_nul(prop.value().unwrap()).unwrap();
+ assert_ne!(None, platform_dt.node(path).unwrap());
+ }
+ }
+ }
+
+ #[test]
fn device_info_overlay_iommu() {
let mut fdt_data = fs::read(FDT_FILE_PATH).unwrap();
let mut vm_dtbo_data = fs::read(VM_DTBO_FILE_PATH).unwrap();