pvmfw: Do iommus validation for pkvm-pviommu only
There are VMs not using pkvm-pviommu. For example, some Qualcomm
VMs. In that case, there will be devices using iommus. So the device
node will be having iommus=< >, defined. But it's physical device under
/host node in VM dtbo will not have iommus property. This patch decides
to validate only if the trustable physical node under /host has any iommu.
Otherwise ignore iommus from crosvm and skip validation.
Test: m libpvmfw.device_assignment.test pvmfw
Bug: 380074580
Bug: 385802423
Change-Id: I9ad5d1da9561ec0ae19b0cc6d69d02de2ddffd1f
Signed-off-by: Sreenad Menon <quic_sreemeno@quicinc.com>
diff --git a/guest/pvmfw/src/device_assignment.rs b/guest/pvmfw/src/device_assignment.rs
index fb485fe..efdf4c4 100644
--- a/guest/pvmfw/src/device_assignment.rs
+++ b/guest/pvmfw/src/device_assignment.rs
@@ -373,10 +373,12 @@
// see: DeviceAssignmentInfo::validate_all_regs().
let mut all_iommus = BTreeSet::new();
for physical_device in physical_devices.values() {
- for iommu in &physical_device.iommus {
- if !all_iommus.insert(iommu) {
- error!("Unsupported phys IOMMU duplication found, <iommus> = {iommu:?}");
- return Err(DeviceAssignmentError::UnsupportedIommusDuplication);
+ if let Some(iommus) = &physical_device.iommus {
+ for iommu in iommus {
+ if !all_iommus.insert(iommu) {
+ error!("Unsupported phys IOMMU duplication found, <iommus> = {iommu:?}");
+ return Err(DeviceAssignmentError::UnsupportedIommusDuplication);
+ }
}
}
}
@@ -692,17 +694,17 @@
struct PhysicalDeviceInfo {
target: Phandle,
reg: Vec<DeviceReg>,
- iommus: Vec<(PhysIommu, Sid)>,
+ iommus: Option<Vec<(PhysIommu, Sid)>>,
}
impl PhysicalDeviceInfo {
fn parse_iommus(
node: &FdtNode,
phys_iommus: &BTreeMap<Phandle, PhysIommu>,
- ) -> Result<Vec<(PhysIommu, Sid)>> {
+ ) -> Result<Option<Vec<(PhysIommu, Sid)>>> {
let mut iommus = vec![];
let Some(mut cells) = node.getprop_cells(c"iommus")? else {
- return Ok(iommus);
+ return Ok(None);
};
while let Some(cell) = cells.next() {
// Parse pIOMMU ID
@@ -717,7 +719,7 @@
iommus.push((*iommu, Sid::from(cell)));
}
- Ok(iommus)
+ Ok(Some(iommus))
}
fn parse(node: &FdtNode, phys_iommus: &BTreeMap<Phandle, PhysIommu>) -> Result<Option<Self>> {
@@ -742,7 +744,7 @@
// <interrupts> property from the crosvm DT
interrupts: Vec<u8>,
// Parsed <iommus> property from the crosvm DT. Tuple of PvIommu and vSID.
- iommus: Vec<(PvIommu, Vsid)>,
+ iommus: Option<Vec<(PvIommu, Vsid)>>,
}
impl AssignedDeviceInfo {
@@ -895,8 +897,16 @@
let interrupts = Self::parse_interrupts(&node)?;
- let iommus = Self::parse_iommus(&node, pviommus)?;
- Self::validate_iommus(&iommus, &physical_device.iommus, hypervisor)?;
+ // Ignore <iommus> if no pvIOMMUs are expected based on the VM DTBO, possibly
+ // because physical IOMMUs are being assigned directly.
+ let iommus = if let Some(iommus) = &physical_device.iommus {
+ let parsed_iommus = Self::parse_iommus(&node, pviommus)?;
+ Self::validate_iommus(&parsed_iommus, iommus, hypervisor)?;
+ Some(parsed_iommus)
+ } else {
+ // TODO: Detect misconfigured iommus in input DT.
+ None
+ };
Ok(Some(Self { node_path, reg, interrupts, iommus }))
}
@@ -905,13 +915,16 @@
let mut dst = fdt.node_mut(&self.node_path)?.unwrap();
dst.setprop(c"reg", &to_be_bytes(&self.reg))?;
dst.setprop(c"interrupts", &self.interrupts)?;
- let mut iommus = Vec::with_capacity(8 * self.iommus.len());
- for (pviommu, vsid) in &self.iommus {
- let phandle = pviommu_phandles.get(pviommu).unwrap();
- iommus.extend_from_slice(&u32::from(*phandle).to_be_bytes());
- iommus.extend_from_slice(&vsid.0.to_be_bytes());
+
+ if let Some(iommus) = &self.iommus {
+ let mut iommus_vec = Vec::with_capacity(8 * iommus.len());
+ for (pviommu, vsid) in iommus {
+ let phandle = pviommu_phandles.get(pviommu).unwrap();
+ iommus_vec.extend_from_slice(&u32::from(*phandle).to_be_bytes());
+ iommus_vec.extend_from_slice(&vsid.0.to_be_bytes());
+ }
+ dst.setprop(c"iommus", &iommus_vec)?;
}
- dst.setprop(c"iommus", &iommus)?;
Ok(())
}
@@ -946,10 +959,12 @@
fn validate_pviommu_topology(assigned_devices: &[AssignedDeviceInfo]) -> Result<()> {
let mut all_iommus = BTreeSet::new();
for assigned_device in assigned_devices {
- for iommu in &assigned_device.iommus {
- if !all_iommus.insert(iommu) {
- error!("Unsupported pvIOMMU duplication found, <iommus> = {iommu:?}");
- return Err(DeviceAssignmentError::UnsupportedPvIommusDuplication);
+ if let Some(iommus) = &assigned_device.iommus {
+ for iommu in iommus {
+ if !all_iommus.insert(iommu) {
+ error!("Unsupported pvIOMMU duplication found, <iommus> = {iommu:?}");
+ return Err(DeviceAssignmentError::UnsupportedPvIommusDuplication);
+ }
}
}
}
@@ -1282,6 +1297,8 @@
// TODO(ptosi): Add tests with varying HYP_GRANULE values.
+ // TODO(ptosi): Add tests with iommus.is_none()
+
#[test]
fn device_info_new_without_symbols() {
let mut fdt_data = fs::read(FDT_FILE_PATH).unwrap();
@@ -1329,7 +1346,7 @@
node_path: CString::new("/bus0/backlight").unwrap(),
reg: vec![[0x9, 0xFF].into()],
interrupts: into_fdt_prop(vec![0x0, 0xF, 0x4]),
- iommus: vec![],
+ iommus: Some(vec![]),
}];
assert_eq!(device_info.assigned_devices, expected);
@@ -1354,7 +1371,7 @@
node_path: CString::new("/rng").unwrap(),
reg: vec![[0x9, 0xFF].into()],
interrupts: into_fdt_prop(vec![0x0, 0xF, 0x4]),
- iommus: vec![(PvIommu { id: 0x4 }, Vsid(0xFF0))],
+ iommus: Some(vec![(PvIommu { id: 0x4 }, Vsid(0xFF0))]),
}];
assert_eq!(device_info.assigned_devices, expected);