MCPcopy Create free account
hub / github.com/cloud-hypervisor/cloud-hypervisor / generate_sparse_areas

Method generate_sparse_areas

pci/src/vfio.rs:1551–1649  ·  view source on GitHub ↗
(
        caps: &[VfioRegionInfoCap],
        region_index: u32,
        region_start: u64,
        region_size: u64,
        vfio_msix: Option<&VfioMsix>,
    )

Source from the content-addressed store, hash-verified

1549 }
1550
1551 fn generate_sparse_areas(
1552 caps: &[VfioRegionInfoCap],
1553 region_index: u32,
1554 region_start: u64,
1555 region_size: u64,
1556 vfio_msix: Option<&VfioMsix>,
1557 ) -> Result<Vec<VfioRegionSparseMmapArea>, VfioPciError> {
1558 for cap in caps {
1559 match cap {
1560 VfioRegionInfoCap::SparseMmap(sparse_mmap) => return Ok(sparse_mmap.areas.clone()),
1561 VfioRegionInfoCap::MsixMappable => {
1562 if !is_4k_aligned(region_start) {
1563 error!(
1564 "Region start address 0x{region_start:x} must be at least aligned on 4KiB"
1565 );
1566 return Err(VfioPciError::RegionAlignment);
1567 }
1568 if !is_4k_multiple(region_size) {
1569 error!("Region size 0x{region_size:x} must be at least a multiple of 4KiB");
1570 return Err(VfioPciError::RegionSize);
1571 }
1572
1573 // In case the region contains the MSI-X vectors table or
1574 // the MSI-X PBA table, we must calculate the subregions
1575 // around them, leading to a list of sparse areas.
1576 // We want to make sure we will still trap MMIO accesses
1577 // to these MSI-X specific ranges. If these region don't align
1578 // with pagesize, we can achieve it by enlarging its range.
1579 //
1580 // Using a BtreeMap as the list provided through the iterator is sorted
1581 // by key. This ensures proper split of the whole region.
1582 let mut inter_ranges = BTreeMap::new();
1583 if let Some(msix) = vfio_msix {
1584 if region_index == msix.cap.table_bir() {
1585 let (offset, size) = msix.cap.table_range();
1586 let offset = align_page_size_down(offset);
1587 let size = align_page_size_up(size);
1588 // MSI-X mmap region safety: when a device has a non page
1589 // aligned MSI-X offset, fixup_msix_region() relocates MSI-X
1590 // to the upper half of an enlarged virtual BAR, causing the
1591 // offsets in msix.cap to exceed the physical BAR size. This
1592 // check skips carving a hole, preventing invalid offsets from
1593 // reaching the mmap path. With no holes,
1594 // generate_sparse_areas() returns a single sparse region
1595 // covering the entire physical BAR. The relocated MSI-X in
1596 // the virtual BAR remains trapped because its upper half has
1597 // no mmap backing. Exposing the physical MSI-X region through
1598 // mmap is safe when the kernel advertises
1599 // VFIO_REGION_INFO_CAP_MSIX_MAPPABLE. When MSI-X offsets are
1600 // already page aligned, fixup_msix_region() does not relocate
1601 // and this check is satisfied, so a hole is carved at the
1602 // intended offset as before.
1603 if offset < region_size {
1604 inter_ranges.insert(offset, size);
1605 }
1606 }
1607 if region_index == msix.cap.pba_bir() {
1608 let (offset, size) = msix.cap.pba_range();

Callers

nothing calls this directly

Calls 12

is_4k_alignedFunction · 0.85
is_4k_multipleFunction · 0.85
newFunction · 0.85
align_page_size_downFunction · 0.85
align_page_size_upFunction · 0.85
table_birMethod · 0.80
table_rangeMethod · 0.80
pba_birMethod · 0.80
pba_rangeMethod · 0.80
cloneMethod · 0.45
insertMethod · 0.45
pushMethod · 0.45

Tested by

no test coverage detected