mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 10:10:41 +00:00
devices: virtio: iommu: get iova_max_addr according to ranges' info
Previously the iova_max_addr was got according to the cpu physical address size. Since the cpu physical address is no more than the maximum iova size provided by hardware iommu, the iova space size can work for any passthrough devices. But it may not utilize the whole iova space, as the iova size isn't got from the underlying hardware iommu. This patch introduces a way to get iova_max_addr according to the iommu ranges' info, therefore the iova_max_addr can be precisely calculated. BUG=b:185084350 TEST=Boot a crosvm guest with vIOMMU enabled Change-Id: I4ed37bf158208d61663a4bf474549df4fce3adf5 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3580373 Reviewed-by: David Stevens <stevensd@chromium.org> Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org> Commit-Queue: David Stevens <stevensd@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
349247860c
commit
c834b038c2
6 changed files with 52 additions and 15 deletions
|
@ -1472,6 +1472,11 @@ impl VfioPciDevice {
|
|||
Ok(ranges)
|
||||
}
|
||||
|
||||
/// Return the supported iova max address of the Vfio Pci device
|
||||
pub fn get_max_iova(&self) -> u64 {
|
||||
self.device.get_max_addr()
|
||||
}
|
||||
|
||||
#[cfg(feature = "direct")]
|
||||
fn coordinated_pm(sysfs_path: &Path, enter: bool) -> anyhow::Result<()> {
|
||||
let path = Path::new(sysfs_path).join("power/coordinated");
|
||||
|
|
|
@ -702,7 +702,7 @@ pub struct VfioDevice {
|
|||
// vec for vfio device's regions
|
||||
regions: Vec<VfioRegion>,
|
||||
|
||||
iova_alloc: Option<Arc<Mutex<AddressAllocator>>>,
|
||||
iova_alloc: Arc<Mutex<AddressAllocator>>,
|
||||
}
|
||||
|
||||
impl VfioDevice {
|
||||
|
@ -731,6 +731,14 @@ impl VfioDevice {
|
|||
group.lock().add_device_num();
|
||||
let group_descriptor = group.lock().as_raw_descriptor();
|
||||
|
||||
let iova_ranges = container
|
||||
.lock()
|
||||
.vfio_iommu_iova_get_iova_ranges()?
|
||||
.into_iter()
|
||||
.map(|r| std::ops::RangeInclusive::new(r.start, r.end));
|
||||
let iova_alloc = AddressAllocator::new_from_list(iova_ranges, None, None)
|
||||
.map_err(VfioError::Resources)?;
|
||||
|
||||
Ok(VfioDevice {
|
||||
dev,
|
||||
name,
|
||||
|
@ -738,7 +746,7 @@ impl VfioDevice {
|
|||
group_descriptor,
|
||||
group_id,
|
||||
regions,
|
||||
iova_alloc: None,
|
||||
iova_alloc: Arc::new(Mutex::new(iova_alloc)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -787,7 +795,7 @@ impl VfioDevice {
|
|||
group_descriptor,
|
||||
group_id,
|
||||
regions,
|
||||
iova_alloc: Some(Arc::new(Mutex::new(iova_alloc))),
|
||||
iova_alloc: Arc::new(Mutex::new(iova_alloc)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1352,13 +1360,14 @@ impl VfioDevice {
|
|||
}
|
||||
|
||||
pub fn alloc_iova(&self, size: u64, align_size: u64, alloc: Alloc) -> Result<u64> {
|
||||
match &self.iova_alloc {
|
||||
None => Err(VfioError::NoRescAlloc),
|
||||
Some(iova_alloc) => iova_alloc
|
||||
.lock()
|
||||
.allocate_with_align(size, alloc, "alloc_iova".to_owned(), align_size)
|
||||
.map_err(VfioError::Resources),
|
||||
}
|
||||
self.iova_alloc
|
||||
.lock()
|
||||
.allocate_with_align(size, alloc, "alloc_iova".to_owned(), align_size)
|
||||
.map_err(VfioError::Resources)
|
||||
}
|
||||
|
||||
pub fn get_max_addr(&self) -> u64 {
|
||||
self.iova_alloc.lock().get_max_addr()
|
||||
}
|
||||
|
||||
/// Gets the vfio device backing `File`.
|
||||
|
|
|
@ -747,7 +747,7 @@ impl Iommu {
|
|||
pub fn new(
|
||||
base_features: u64,
|
||||
endpoints: BTreeMap<u32, Arc<Mutex<Box<dyn MemoryMapperTrait>>>>,
|
||||
phys_max_addr: u64,
|
||||
iova_max_addr: u64,
|
||||
hp_endpoints_ranges: Vec<RangeInclusive<u32>>,
|
||||
translate_response_senders: Option<BTreeMap<u32, Tube>>,
|
||||
translate_request_rx: Option<Tube>,
|
||||
|
@ -767,7 +767,7 @@ impl Iommu {
|
|||
|
||||
let input_range = virtio_iommu_range_64 {
|
||||
start: Le64::from(0),
|
||||
end: phys_max_addr.into(),
|
||||
end: iova_max_addr.into(),
|
||||
};
|
||||
|
||||
let config = virtio_iommu_config {
|
||||
|
|
|
@ -277,6 +277,11 @@ impl AddressAllocator {
|
|||
.map(|(&alloc, _)| alloc)
|
||||
}
|
||||
|
||||
// Return the max address of the allocated address ranges.
|
||||
pub fn get_max_addr(&self) -> u64 {
|
||||
self.regions.iter().fold(0, |x, (_, end)| x.max(*end))
|
||||
}
|
||||
|
||||
/// Returns allocation associated with `alloc`, or None if no such allocation exists.
|
||||
pub fn get(&self, alloc: &Alloc) -> Option<&(u64, u64, String)> {
|
||||
self.allocs.get(alloc)
|
||||
|
@ -764,4 +769,15 @@ mod tests {
|
|||
Err(Error::InvalidAlloc(anon))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_max_address_of_ranges() {
|
||||
let ranges = vec![
|
||||
RangeInclusive::new(0x1000, 0xFFFF),
|
||||
RangeInclusive::new(0x20000, 0xFFFFF),
|
||||
];
|
||||
let pool = AddressAllocator::new_from_list(ranges.into_iter(), None, None).unwrap();
|
||||
|
||||
assert_eq!(pool.get_max_addr(), 0xFFFFF);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -996,7 +996,7 @@ pub fn create_pmem_device(
|
|||
|
||||
pub fn create_iommu_device(
|
||||
cfg: &Config,
|
||||
phys_max_addr: u64,
|
||||
iova_max_addr: u64,
|
||||
endpoints: BTreeMap<u32, Arc<Mutex<Box<dyn MemoryMapperTrait>>>>,
|
||||
hp_endpoints_ranges: Vec<RangeInclusive<u32>>,
|
||||
translate_response_senders: Option<BTreeMap<u32, Tube>>,
|
||||
|
@ -1006,7 +1006,7 @@ pub fn create_iommu_device(
|
|||
let dev = virtio::Iommu::new(
|
||||
virtio::base_features(cfg.protected_vm),
|
||||
endpoints,
|
||||
phys_max_addr,
|
||||
iova_max_addr,
|
||||
hp_endpoints_ranges,
|
||||
translate_response_senders,
|
||||
translate_request_rx,
|
||||
|
|
|
@ -483,6 +483,7 @@ fn create_devices(
|
|||
#[cfg(feature = "gpu")] render_server_fd: Option<SafeDescriptor>,
|
||||
vvu_proxy_device_tubes: &mut Vec<Tube>,
|
||||
vvu_proxy_max_sibling_mem_size: u64,
|
||||
iova_max_addr: &mut Option<u64>,
|
||||
) -> DeviceResult<Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)>> {
|
||||
let mut devices: Vec<(Box<dyn BusDeviceObj>, Option<Minijail>)> = Vec::new();
|
||||
let mut balloon_inflate_tube: Option<Tube> = None;
|
||||
|
@ -508,6 +509,10 @@ fn create_devices(
|
|||
vfio_dev.iommu_dev_type(),
|
||||
)?;
|
||||
|
||||
*iova_max_addr = Some(max(
|
||||
vfio_pci_device.get_max_iova(),
|
||||
iova_max_addr.unwrap_or(0),
|
||||
));
|
||||
devices.push((vfio_pci_device, jail));
|
||||
}
|
||||
|
||||
|
@ -1297,6 +1302,7 @@ where
|
|||
|
||||
let mut iommu_attached_endpoints: BTreeMap<u32, Arc<Mutex<Box<dyn MemoryMapperTrait>>>> =
|
||||
BTreeMap::new();
|
||||
let mut iova_max_addr: Option<u64> = None;
|
||||
let mut devices = create_devices(
|
||||
&cfg,
|
||||
&mut vm,
|
||||
|
@ -1320,6 +1326,7 @@ where
|
|||
render_server_fd,
|
||||
&mut vvu_proxy_device_tubes,
|
||||
components.memory_size,
|
||||
&mut iova_max_addr,
|
||||
)?;
|
||||
|
||||
let mut hp_endpoints_ranges: Vec<RangeInclusive<u32>> = Vec::new();
|
||||
|
@ -1356,7 +1363,7 @@ where
|
|||
let (iommu_host_tube, iommu_device_tube) = Tube::pair().context("failed to create tube")?;
|
||||
let iommu_dev = create_iommu_device(
|
||||
&cfg,
|
||||
(1u64 << vm.get_guest_phys_addr_bits()) - 1,
|
||||
iova_max_addr.unwrap_or(u64::MAX),
|
||||
iommu_attached_endpoints,
|
||||
hp_endpoints_ranges,
|
||||
translate_response_senders,
|
||||
|
|
Loading…
Reference in a new issue