pvmfw: Parse incoming <reg> and <iommus>
Bug: 277993056
Test: atest libpvmfw.device_assignment.test, launch protected VM
Change-Id: I20c09cc7518796ec8adbc5d45f0f51a6d75a0062
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index d267e2e..aa9942c 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -73,6 +73,7 @@
srcs: ["src/device_assignment.rs"],
defaults: ["libpvmfw.test.defaults"],
rustlibs: [
+ "libhyp",
"liblibfdt",
"liblog_rust",
"libpvmfw_fdt_template",
@@ -84,6 +85,7 @@
":test_pvmfw_devices_with_multiple_devices_iommus",
":test_pvmfw_devices_with_iommu_sharing",
":test_pvmfw_devices_with_iommu_id_conflict",
+ ":test_pvmfw_devices_without_device",
":test_pvmfw_devices_without_iommus",
],
// To use libpvmfw_fdt_template for testing
@@ -142,6 +144,13 @@
}
genrule {
+ name: "test_pvmfw_devices_without_device",
+ defaults: ["test_device_assignment_dts_to_dtb"],
+ srcs: ["testdata/test_pvmfw_devices_without_device.dts"],
+ out: ["test_pvmfw_devices_without_device.dtb"],
+}
+
+genrule {
name: "test_pvmfw_devices_with_multiple_devices_iommus",
defaults: ["test_device_assignment_dts_to_dtb"],
srcs: ["testdata/test_pvmfw_devices_with_multiple_devices_iommus.dts"],
diff --git a/pvmfw/src/device_assignment.rs b/pvmfw/src/device_assignment.rs
index 14f1fe5..19ace5f 100644
--- a/pvmfw/src/device_assignment.rs
+++ b/pvmfw/src/device_assignment.rs
@@ -27,7 +27,9 @@
use core::ffi::CStr;
use core::iter::Iterator;
use core::mem;
-use libfdt::{Fdt, FdtError, FdtNode, Phandle};
+use hyp::DeviceAssigningHypervisor;
+use libfdt::{Fdt, FdtError, FdtNode, Phandle, Reg};
+use log::error;
// TODO(b/308694211): Use cstr! from vmbase instead.
macro_rules! cstr {
@@ -47,10 +49,12 @@
/// Errors in device assignment.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DeviceAssignmentError {
- // Invalid VM DTBO
+ /// Invalid VM DTBO
InvalidDtbo,
/// Invalid __symbols__
InvalidSymbols,
+ /// Invalid <reg>
+ InvalidReg,
/// Invalid <interrupts>
InvalidInterrupts,
/// Invalid <iommus>
@@ -83,6 +87,7 @@
f,
"Invalid property in /__symbols__. Must point to valid assignable device node."
),
+ Self::InvalidReg => write!(f, "Invalid <reg>"),
Self::InvalidInterrupts => write!(f, "Invalid <interrupts>"),
Self::InvalidIommus => write!(f, "Invalid <iommus>"),
Self::InvalidPvIommu => write!(f, "Invalid pvIOMMU node"),
@@ -214,6 +219,36 @@
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
struct Vsid(u32);
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+struct DeviceReg {
+ addr: u64,
+ size: u64,
+}
+
+impl TryFrom<Reg<u64>> for DeviceReg {
+ type Error = DeviceAssignmentError;
+
+ fn try_from(reg: Reg<u64>) -> Result<Self> {
+ Ok(Self { addr: reg.addr, size: reg.size.ok_or(DeviceAssignmentError::InvalidReg)? })
+ }
+}
+
+fn parse_node_reg(node: &FdtNode) -> Result<Vec<DeviceReg>> {
+ node.reg()?
+ .ok_or(DeviceAssignmentError::InvalidReg)?
+ .map(DeviceReg::try_from)
+ .collect::<Result<Vec<_>>>()
+}
+
+fn to_be_bytes(reg: &[DeviceReg]) -> Vec<u8> {
+ let mut reg_cells = vec![];
+ for x in reg {
+ reg_cells.extend_from_slice(&x.addr.to_be_bytes());
+ reg_cells.extend_from_slice(&x.size.to_be_bytes());
+ }
+ reg_cells
+}
+
/// Assigned device information parsed from crosvm DT.
/// Keeps everything in the owned data because underlying FDT will be reused for platform DT.
#[derive(Debug, Eq, PartialEq)]
@@ -223,7 +258,7 @@
// DTBO node path of the assigned device (e.g. "/fragment@rng/__overlay__/rng")
dtbo_node_path: CString,
// <reg> property from the crosvm DT
- reg: Vec<u8>,
+ reg: Vec<DeviceReg>,
// <interrupts> property from the crosvm DT
interrupts: Vec<u8>,
// Parsed <iommus> property from the crosvm DT. Tuple of PvIommu and vSID.
@@ -231,6 +266,22 @@
}
impl AssignedDeviceInfo {
+ fn parse_reg(
+ node: &FdtNode,
+ hypervisor: &dyn DeviceAssigningHypervisor,
+ ) -> Result<Vec<DeviceReg>> {
+ let device_reg = parse_node_reg(node)?;
+ // TODO(b/277993056): Valid the result back with physical reg
+ for reg in &device_reg {
+ hypervisor.get_phys_mmio_token(reg.addr, reg.size).map_err(|e| {
+ let name = node.name();
+ error!("Failed to validate device <reg>, error={e:?}, name={name:?}, reg={reg:?}");
+ DeviceAssignmentError::InvalidReg
+ })?;
+ }
+ Ok(device_reg)
+ }
+
fn parse_interrupts(node: &FdtNode) -> Result<Vec<u8>> {
// Validation: Validate if interrupts cell numbers are multiple of #interrupt-cells.
// We can't know how many interrupts would exist.
@@ -250,6 +301,7 @@
fn parse_iommus(
node: &FdtNode,
pviommus: &BTreeMap<Phandle, PvIommu>,
+ hypervisor: &dyn DeviceAssigningHypervisor,
) -> Result<Vec<(PvIommu, Vsid)>> {
let mut iommus = vec![];
let Some(mut cells) = node.getprop_cells(cstr!("iommus"))? else {
@@ -266,6 +318,15 @@
};
let vsid = Vsid(cell);
+ // TODO(b/277993056): Valid the result back with phys iommu id and sid..
+ hypervisor
+ .get_phys_iommu_token(pviommu.id.into(), vsid.0.into())
+ .map_err(|e| {
+ let name = node.name().unwrap_or_default();
+ error!("Failed to validate device <iommus>, error={e:?}, name={name:?}, pviommu={pviommu:?}, vsid={:?}", vsid.0);
+ DeviceAssignmentError::InvalidIommus
+ })?;
+
iommus.push((*pviommu, vsid));
}
Ok(iommus)
@@ -276,27 +337,21 @@
vm_dtbo: &VmDtbo,
dtbo_node_path: &CStr,
pviommus: &BTreeMap<Phandle, PvIommu>,
+ hypervisor: &dyn DeviceAssigningHypervisor,
) -> Result<Option<Self>> {
let node_path = vm_dtbo.locate_overlay_target_path(dtbo_node_path)?;
let Some(node) = fdt.node(&node_path)? else { return Ok(None) };
- // TODO(b/277993056): Validate reg with HVC, and keep reg with FdtNode::reg()
- let reg = node.getprop(cstr!("reg")).unwrap().unwrap();
+ let reg = Self::parse_reg(&node, hypervisor)?;
let interrupts = Self::parse_interrupts(&node)?;
- let iommus = Self::parse_iommus(&node, pviommus)?;
- Ok(Some(Self {
- node_path,
- dtbo_node_path: dtbo_node_path.into(),
- reg: reg.to_vec(),
- interrupts,
- iommus,
- }))
+ let iommus = Self::parse_iommus(&node, pviommus, hypervisor)?;
+ Ok(Some(Self { node_path, dtbo_node_path: dtbo_node_path.into(), reg, interrupts, iommus }))
}
fn patch(&self, fdt: &mut Fdt, pviommu_phandles: &BTreeMap<PvIommu, Phandle>) -> Result<()> {
let mut dst = fdt.node_mut(&self.node_path)?.unwrap();
- dst.setprop(cstr!("reg"), &self.reg)?;
+ dst.setprop(cstr!("reg"), &to_be_bytes(&self.reg))?;
dst.setprop(cstr!("interrupts"), &self.interrupts)?;
let mut iommus = Vec::with_capacity(8 * self.iommus.len());
for (pviommu, vsid) in &self.iommus {
@@ -339,7 +394,11 @@
/// Parses fdt and vm_dtbo, and creates new DeviceAssignmentInfo
// TODO(b/277993056): Parse __local_fixups__
// TODO(b/277993056): Parse __fixups__
- pub fn parse(fdt: &Fdt, vm_dtbo: &VmDtbo) -> Result<Option<Self>> {
+ pub fn 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.
@@ -359,7 +418,7 @@
let dtbo_node_path = CStr::from_bytes_with_nul(symbol_prop_value)
.or(Err(DeviceAssignmentError::InvalidSymbols))?;
let assigned_device =
- AssignedDeviceInfo::parse(fdt, vm_dtbo, dtbo_node_path, &pviommus)?;
+ AssignedDeviceInfo::parse(fdt, vm_dtbo, dtbo_node_path, &pviommus, hypervisor)?;
if let Some(assigned_device) = assigned_device {
assigned_devices.push(assigned_device);
} else {
@@ -446,19 +505,42 @@
#[cfg(test)]
mod tests {
use super::*;
- use alloc::collections::BTreeSet;
+ use alloc::collections::{BTreeMap, BTreeSet};
use std::fs;
const VM_DTBO_FILE_PATH: &str = "test_pvmfw_devices_vm_dtbo.dtbo";
const VM_DTBO_WITHOUT_SYMBOLS_FILE_PATH: &str =
"test_pvmfw_devices_vm_dtbo_without_symbols.dtbo";
const FDT_WITHOUT_IOMMUS_FILE_PATH: &str = "test_pvmfw_devices_without_iommus.dtb";
+ const FDT_WITHOUT_DEVICE_FILE_PATH: &str = "test_pvmfw_devices_without_device.dtb";
const FDT_FILE_PATH: &str = "test_pvmfw_devices_with_rng.dtb";
const FDT_WITH_MULTIPLE_DEVICES_IOMMUS_FILE_PATH: &str =
"test_pvmfw_devices_with_multiple_devices_iommus.dtb";
const FDT_WITH_IOMMU_SHARING: &str = "test_pvmfw_devices_with_iommu_sharing.dtb";
const FDT_WITH_IOMMU_ID_CONFLICT: &str = "test_pvmfw_devices_with_iommu_id_conflict.dtb";
+ #[derive(Debug, Default)]
+ struct MockHypervisor {
+ mmio_tokens: BTreeMap<(u64, u64), u64>,
+ iommu_tokens: BTreeMap<(u64, u64), (u64, u64)>,
+ }
+
+ 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_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 */
+ ))?)
+ }
+ }
+
#[derive(Debug, Eq, PartialEq)]
struct AssignedDeviceNode {
path: CString,
@@ -473,8 +555,7 @@
return Err(FdtError::NotFound.into());
};
- // TODO(b/277993056): Replace DeviceAssignmentError::Internal
- let reg = node.getprop(cstr!("reg"))?.ok_or(DeviceAssignmentError::Internal)?;
+ let reg = node.getprop(cstr!("reg"))?.ok_or(DeviceAssignmentError::InvalidReg)?;
let interrupts = node
.getprop(cstr!("interrupts"))?
.ok_or(DeviceAssignmentError::InvalidInterrupts)?;
@@ -524,6 +605,12 @@
v
}
+ impl From<[u64; 2]> for DeviceReg {
+ fn from(fdt_cells: [u64; 2]) -> Self {
+ DeviceReg { addr: fdt_cells[0], size: fdt_cells[1] }
+ }
+ }
+
#[test]
fn device_info_new_without_symbols() {
let mut fdt_data = fs::read(FDT_FILE_PATH).unwrap();
@@ -531,7 +618,20 @@
let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap();
let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
- let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo).unwrap();
+ let hypervisor: MockHypervisor = Default::default();
+ let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor).unwrap();
+ assert_eq!(device_info, None);
+ }
+
+ #[test]
+ fn device_info_new_without_device() {
+ let mut fdt_data = fs::read(FDT_WITHOUT_DEVICE_FILE_PATH).unwrap();
+ let mut vm_dtbo_data = fs::read(VM_DTBO_FILE_PATH).unwrap();
+ let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap();
+ let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
+
+ let hypervisor: MockHypervisor = Default::default();
+ let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor).unwrap();
assert_eq!(device_info, None);
}
@@ -542,12 +642,16 @@
let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap();
let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
- let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo).unwrap().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();
let expected = [AssignedDeviceInfo {
node_path: CString::new("/backlight").unwrap(),
dtbo_node_path: cstr!("/fragment@backlight/__overlay__/backlight").into(),
- reg: into_fdt_prop(vec![0x0, 0x9, 0x0, 0xFF]),
+ reg: vec![[0x9, 0xFF].into()],
interrupts: into_fdt_prop(vec![0x0, 0xF, 0x4]),
iommus: vec![],
}];
@@ -562,12 +666,16 @@
let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap();
let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
- let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo).unwrap().unwrap();
+ let hypervisor = MockHypervisor {
+ mmio_tokens: [((0x9, 0xFF), 0x12F00000)].into(),
+ iommu_tokens: [((0x4, 0xFF0), (0x12E40000, 0x3))].into(),
+ };
+ let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor).unwrap().unwrap();
let expected = [AssignedDeviceInfo {
node_path: CString::new("/rng").unwrap(),
dtbo_node_path: cstr!("/fragment@rng/__overlay__/rng").into(),
- reg: into_fdt_prop(vec![0x0, 0x9, 0x0, 0xFF]),
+ reg: vec![[0x9, 0xFF].into()],
interrupts: into_fdt_prop(vec![0x0, 0xF, 0x4]),
iommus: vec![(PvIommu { id: 0x4 }, Vsid(0xFF0))],
}];
@@ -583,7 +691,8 @@
let fdt = Fdt::create_empty_tree(&mut fdt_data).unwrap();
let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
- let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo).unwrap();
+ let hypervisor: MockHypervisor = Default::default();
+ let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor).unwrap();
assert_eq!(device_info, None);
}
@@ -594,7 +703,11 @@
let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap();
let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
- let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo).unwrap().unwrap();
+ let hypervisor = MockHypervisor {
+ mmio_tokens: [((0x9, 0xFF), 0x12F00000)].into(),
+ iommu_tokens: [((0x4, 0xFF0), (0x12E40000, 0x3))].into(),
+ };
+ let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor).unwrap().unwrap();
device_info.filter(vm_dtbo).unwrap();
let vm_dtbo = vm_dtbo.as_mut();
@@ -624,7 +737,11 @@
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 device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo).unwrap().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.
@@ -669,7 +786,11 @@
let platform_dt = Fdt::from_mut_slice(&mut platform_dt_data).unwrap();
platform_dt.unpack().unwrap();
- let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo).unwrap().unwrap();
+ let hypervisor = MockHypervisor {
+ mmio_tokens: [((0x9, 0xFF), 0x12F00000)].into(),
+ iommu_tokens: [((0x4, 0xFF0), (0x12E40000, 0x3))].into(),
+ };
+ 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.
@@ -703,7 +824,21 @@
let platform_dt = Fdt::from_mut_slice(&mut platform_dt_data).unwrap();
platform_dt.unpack().unwrap();
- let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo).unwrap().unwrap();
+ let hypervisor = MockHypervisor {
+ mmio_tokens: [
+ ((0x9, 0xFF), 0x12F00000),
+ ((0x100, 0x1000), 0xF00000),
+ ((0x200, 0x1000), 0xF10000),
+ ]
+ .into(),
+ iommu_tokens: [
+ ((0x4, 0xFF0), (0x12E40000, 3)),
+ ((0x40, 0xFFA), (0x40000, 0x4)),
+ ((0x50, 0xFFB), (0x50000, 0x5)),
+ ]
+ .into(),
+ };
+ 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.
@@ -721,7 +856,7 @@
},
AssignedDeviceNode {
path: CString::new("/light").unwrap(),
- reg: into_fdt_prop(vec![0x100, 0x9]),
+ reg: into_fdt_prop(vec![0x0, 0x100, 0x0, 0x1000, 0x0, 0x200, 0x0, 0x1000]),
interrupts: into_fdt_prop(vec![0x0, 0xF, 0x5]),
iommus: vec![0x40, 0xFFA, 0x50, 0xFFB],
},
@@ -746,7 +881,11 @@
let platform_dt = Fdt::from_mut_slice(&mut platform_dt_data).unwrap();
platform_dt.unpack().unwrap();
- let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo).unwrap().unwrap();
+ let hypervisor = MockHypervisor {
+ mmio_tokens: [((0x9, 0xFF), 0x12F00000), ((0x100, 0x9), 0x12000000)].into(),
+ iommu_tokens: [((0x4, 0xFF0), (0x12E40000, 3))].into(),
+ };
+ 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.
@@ -764,7 +903,7 @@
},
AssignedDeviceNode {
path: CString::new("/led").unwrap(),
- reg: into_fdt_prop(vec![0x100, 0x9]),
+ reg: into_fdt_prop(vec![0x0, 0x100, 0x0, 0x9]),
interrupts: into_fdt_prop(vec![0x0, 0xF, 0x5]),
iommus: vec![0x4, 0xFF0],
},
@@ -786,8 +925,44 @@
let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap();
let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
- let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo);
+ let hypervisor = MockHypervisor {
+ mmio_tokens: [((0x9, 0xFF), 0x12F00000)].into(),
+ iommu_tokens: [((0x4, 0xFF0), (0x12E40000, 0x3))].into(),
+ };
+ let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor);
assert_eq!(device_info, Err(DeviceAssignmentError::DuplicatedPvIommuIds));
}
+
+ #[test]
+ fn device_info_invalid_reg() {
+ let mut fdt_data = fs::read(FDT_FILE_PATH).unwrap();
+ let mut vm_dtbo_data = fs::read(VM_DTBO_FILE_PATH).unwrap();
+ let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap();
+ let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
+
+ let hypervisor = MockHypervisor {
+ mmio_tokens: BTreeMap::new(),
+ iommu_tokens: [((0x4, 0xFF0), (0x12E40000, 0x3))].into(),
+ };
+ let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor);
+
+ assert_eq!(device_info, Err(DeviceAssignmentError::InvalidReg));
+ }
+
+ #[test]
+ fn device_info_invalid_iommus() {
+ let mut fdt_data = fs::read(FDT_FILE_PATH).unwrap();
+ let mut vm_dtbo_data = fs::read(VM_DTBO_FILE_PATH).unwrap();
+ let fdt = Fdt::from_mut_slice(&mut fdt_data).unwrap();
+ let vm_dtbo = VmDtbo::from_mut_slice(&mut vm_dtbo_data).unwrap();
+
+ let hypervisor = MockHypervisor {
+ mmio_tokens: [((0x9, 0xFF), 0x12F00000)].into(),
+ iommu_tokens: BTreeMap::new(),
+ };
+ let device_info = DeviceAssignmentInfo::parse(fdt, vm_dtbo, &hypervisor);
+
+ assert_eq!(device_info, Err(DeviceAssignmentError::InvalidIommus));
+ }
}
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 5fbc767..628296a 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -15,8 +15,7 @@
//! High-level FDT functions.
use crate::bootargs::BootArgsIterator;
-use crate::device_assignment::DeviceAssignmentInfo;
-use crate::device_assignment::VmDtbo;
+use crate::device_assignment::{DeviceAssignmentInfo, VmDtbo};
use crate::helpers::GUEST_PAGE_SIZE;
use crate::Box;
use crate::RebootReason;
@@ -711,10 +710,19 @@
validate_swiotlb_info(&swiotlb_info, &memory_range)?;
let device_assignment = match vm_dtbo {
- Some(vm_dtbo) => DeviceAssignmentInfo::parse(fdt, vm_dtbo).map_err(|e| {
- error!("Failed to parse device assignment from DT and VM DTBO: {e}");
- RebootReason::InvalidFdt
- })?,
+ Some(vm_dtbo) => {
+ if let Some(hypervisor) = hyp::get_device_assigner() {
+ DeviceAssignmentInfo::parse(fdt, vm_dtbo, hypervisor).map_err(|e| {
+ error!("Failed to parse device assignment from DT and VM DTBO: {e}");
+ RebootReason::InvalidFdt
+ })?
+ } else {
+ warn!(
+ "Device assignment is ignored because device assigning hypervisor is missing"
+ );
+ None
+ }
+ }
None => None,
};
diff --git a/pvmfw/testdata/test_pvmfw_devices_vm_dtbo.dts b/pvmfw/testdata/test_pvmfw_devices_vm_dtbo.dts
index da08694..691d15a 100644
--- a/pvmfw/testdata/test_pvmfw_devices_vm_dtbo.dts
+++ b/pvmfw/testdata/test_pvmfw_devices_vm_dtbo.dts
@@ -21,7 +21,7 @@
light {
compatible = "android,light";
version = <0x1 0x2>;
- android,pvmfw,phy-reg = <0x0 0xF00000 0x1000>;
+ android,pvmfw,phy-reg = <0x0 0xF00000 0x1000>, <0x0 0xF10000 0x1000>;
android,pvmfw,phy-iommu = <0x0 0x40000>, <0x0 0x50000>;
android,pvmfw,phy-sid = <4>, <5>;
};
diff --git a/pvmfw/testdata/test_pvmfw_devices_with_iommu_id_conflict.dts b/pvmfw/testdata/test_pvmfw_devices_with_iommu_id_conflict.dts
index 70b633c..a9e30be 100644
--- a/pvmfw/testdata/test_pvmfw_devices_with_iommu_id_conflict.dts
+++ b/pvmfw/testdata/test_pvmfw_devices_with_iommu_id_conflict.dts
@@ -27,7 +27,7 @@
light@70000000 {
compatible = "android,light";
- reg = <0x100 0x9>;
+ reg = <0x0 0x100 0x0 0x100>, <0x0 0x200 0x0 0x100>;
interrupts = <0x0 0xF 0x5>;
iommus = <&pviommu_a 0xA>, <&pviommu_b 0xB>;
};
diff --git a/pvmfw/testdata/test_pvmfw_devices_with_iommu_sharing.dts b/pvmfw/testdata/test_pvmfw_devices_with_iommu_sharing.dts
index 7c6d2f2..78ff868 100644
--- a/pvmfw/testdata/test_pvmfw_devices_with_iommu_sharing.dts
+++ b/pvmfw/testdata/test_pvmfw_devices_with_iommu_sharing.dts
@@ -14,8 +14,8 @@
};
led@70000000 {
- compatible = "android,light";
- reg = <0x100 0x9>;
+ compatible = "android,led";
+ reg = <0x0 0x100 0x0 0x9>;
interrupts = <0x0 0xF 0x5>;
iommus = <&pviommu_0 0xFF0>;
};
diff --git a/pvmfw/testdata/test_pvmfw_devices_with_multiple_devices_iommus.dts b/pvmfw/testdata/test_pvmfw_devices_with_multiple_devices_iommus.dts
index 76c99c9..ca7e7f3 100644
--- a/pvmfw/testdata/test_pvmfw_devices_with_multiple_devices_iommus.dts
+++ b/pvmfw/testdata/test_pvmfw_devices_with_multiple_devices_iommus.dts
@@ -20,7 +20,7 @@
light@70000000 {
compatible = "android,light";
- reg = <0x100 0x9>;
+ reg = <0x0 0x100 0x0 0x1000>, <0x0 0x200 0x0 0x1000>;
interrupts = <0x0 0xF 0x5>;
iommus = <&pviommu_a 0xFFA>, <&pviommu_b 0xFFB>;
};
diff --git a/pvmfw/testdata/test_pvmfw_devices_without_device.dts b/pvmfw/testdata/test_pvmfw_devices_without_device.dts
new file mode 100644
index 0000000..ee0be3a
--- /dev/null
+++ b/pvmfw/testdata/test_pvmfw_devices_without_device.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+/plugin/;
+
+/include/ "test_crosvm_dt_base.dtsi"
+
+/ {
+};