The vfio_known_safe_misalignment() whitelist (currently TPM CRB only) requires a new entry every time a device exposes a non-page-aligned region, which does not scale.
Replace it with a DMA capability check: a region that is not page-aligned or is smaller than a host page can never be a valid DMA target, so a page-offset mismatch is harmless and only traced. Only warn for page-aligned, page-sized regions where the mismatch could indicate a real mapping problem. This removes the TPM CRB dependency from the VFIO listener and eliminates the need for per-device whitelisting entirely. Suggested-by: Peter Maydell <[email protected]> Link: https://lore.kernel.org/qemu-devel/[email protected] Signed-off-by: Cédric Le Goater <[email protected]> --- hw/vfio/listener.c | 47 +++++++++++++++++++++++++------------------- hw/vfio/trace-events | 2 +- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/hw/vfio/listener.c b/hw/vfio/listener.c index c19600e980a8d02217b5d9df4aca8f879ab2c5d5..f2c3603a920b99002630d6f47af5bbbdfed8be86 100644 --- a/hw/vfio/listener.c +++ b/hw/vfio/listener.c @@ -40,7 +40,6 @@ #include "migration/misc.h" #include "migration/qemu-file.h" #include "system/tcg.h" -#include "system/tpm.h" #include "vfio-migration-internal.h" #include "vfio-helpers.h" #include "vfio-listener.h" @@ -352,20 +351,17 @@ static void vfio_ram_discard_unregister_listener(VFIOContainer *bcontainer, g_free(vrdl); } -static bool vfio_known_safe_misalignment(MemoryRegionSection *section) +static bool vfio_section_misaligned(MemoryRegionSection *section) { - MemoryRegion *mr = section->mr; - - if (!TPM_IS_CRB(mr->owner)) { - return false; - } + return (section->offset_within_address_space & ~qemu_real_host_page_mask()) != + (section->offset_within_region & ~qemu_real_host_page_mask()); +} - /* this is a known safe misaligned region, just trace for debug purpose */ - trace_vfio_known_safe_misalignment(memory_region_name(mr), - section->offset_within_address_space, - section->offset_within_region, - qemu_real_host_page_size()); - return true; +static bool vfio_section_dma_capable(MemoryRegionSection *section) +{ + return QEMU_IS_ALIGNED(section->offset_within_address_space, + qemu_real_host_page_size()) && + int128_ge(section->size, int128_make64(qemu_real_host_page_size())); } static bool vfio_listener_valid_section(MemoryRegionSection *section, @@ -379,17 +375,28 @@ static bool vfio_listener_valid_section(MemoryRegionSection *section, return false; } - if (unlikely((section->offset_within_address_space & - ~qemu_real_host_page_mask()) != - (section->offset_within_region & ~qemu_real_host_page_mask()))) { - if (!vfio_known_safe_misalignment(section)) { - error_report("%s received unaligned region %s iova=0x%"PRIx64 + if (unlikely(vfio_section_misaligned(section))) { + /* + * A region that is not page-aligned or is smaller than a host + * page can never be a valid DMA target, so the misalignment is + * harmless. Only warn for page-aligned, page-sized regions + * where the offset mismatch could indicate a real problem. + */ + if (vfio_section_dma_capable(section)) { + error_report("vfio: region %s page-offset mismatch prevents" + " DMA mapping (iova=0x%"PRIx64 " offset_within_region=0x%"PRIx64 - " qemu_real_host_page_size=0x%"PRIxPTR, - __func__, memory_region_name(section->mr), + " page_size=0x%"PRIxPTR ")", + memory_region_name(section->mr), section->offset_within_address_space, section->offset_within_region, qemu_real_host_page_size()); + } else { + trace_vfio_listener_region_misaligned( + memory_region_name(section->mr), + section->offset_within_address_space, + section->offset_within_region, + qemu_real_host_page_size()); } return false; } diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index bfdaf229e42b0d9d40e38c828c97cf47eb831a87..8cbad9ad0f3a4cbcbb3b5f00ac7afe392a821071 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -99,7 +99,7 @@ vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn vfio_listener_region_add_iommu(const char* name, uint64_t start, uint64_t end) "region_add [iommu] %s 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_del_iommu(const char *name) "region_del [iommu] %s" vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]" -vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR +vfio_listener_region_misaligned(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA" vfio_listener_region_skip_dma_map(const char *name, uint64_t iova, uint64_t size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" marked to skip IOMMU mapping" vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 -- 2.54.0
