On Tue, May 14, 2013 at 11:48:47AM +0200, Paolo Bonzini wrote: > Il 14/05/2013 11:13, David Gibson ha scritto: > > This patch uses the new IOMMU notifiers to allow VFIO pass through devices > > to work with guest side IOMMUs, as long as the host-side VFIO iommu has > > sufficient capability and granularity to match the guest side. This works > > by tracking all map and unmap operations on the guest IOMMU using the > > notifiers, and mirroring them into VFIO. > > > > There are a number of FIXMEs, and the scheme involves rather more notifier > > structures than I'd like, but it shuold make for a reasonable proof of > > concept. > > > > Signed-off-by: David Gibson <da...@gibson.dropbear.id.au> > > --- > > hw/misc/vfio.c | 139 > > ++++++++++++++++++++++++++++++++++++++++++++++++++------ > > 1 file changed, 126 insertions(+), 13 deletions(-) > > > > diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c > > index f4e3792..62a83ca 100644 > > --- a/hw/misc/vfio.c > > +++ b/hw/misc/vfio.c > > @@ -133,10 +133,18 @@ typedef struct VFIOContainer { > > }; > > void (*release)(struct VFIOContainer *); > > } iommu_data; > > + QLIST_HEAD(, VFIOGuestIOMMU) guest_iommus; > > QLIST_HEAD(, VFIOGroup) group_list; > > QLIST_ENTRY(VFIOContainer) next; > > } VFIOContainer; > > > > +typedef struct VFIOGuestIOMMU { > > + VFIOContainer *container; > > + MemoryRegion *iommu; > > + Notifier n; > > + QLIST_ENTRY(VFIOGuestIOMMU) list; > > +} VFIOGuestIOMMU; > > + > > /* Cache of MSI-X setup plus extra mmap and memory region for split BAR > > map */ > > typedef struct VFIOMSIXInfo { > > uint8_t table_bar; > > @@ -1940,7 +1948,64 @@ static int vfio_dma_map(VFIOContainer *container, > > hwaddr iova, > > > > static bool vfio_listener_skipped_section(MemoryRegionSection *section) > > { > > - return !memory_region_is_ram(section->mr); > > + return !memory_region_is_ram(section->mr) && > > + !memory_region_is_iommu(section->mr); > > +} > > + > > +static void vfio_iommu_map_notify(Notifier *n, void *data) > > +{ > > + VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); > > + MemoryRegion *iommu = giommu->iommu; > > + VFIOContainer *container = giommu->container; > > + IOMMUTLBEntry *iotlb = data; > > + MemoryRegionSection *mrs; > > + hwaddr xlat; > > + hwaddr len = iotlb->addr_mask + 1; > > + void *vaddr; > > + int ret; > > + > > + DPRINTF("iommu map @ %"HWADDR_PRIx" - %"HWADDR_PRIx"\n", > > + iotlb->iova, iotlb->iova + iotlb->address_mask); > > + > > + /* The IOMMU TLB entry we have just covers translation through > > + * this IOMMU to its immediate target. We need to translate > > + * it the rest of the way through to memory. */ > > + mrs = address_space_translate(iommu->iommu_target_as, > > + iotlb->translated_addr, > > + &xlat, &len, iotlb->perm[1]); > > + if (!memory_region_is_ram(mrs->mr)) { > > + DPRINTF("iommu map to non memory area %"HWADDR_PRIx"\n", > > + xlat); > > + return; > > + } > > + if (len & iotlb->addr_mask) { > > + DPRINTF("iommu has granularity incompatible with target AS\n"); > > + return; > > + } > > + > > + vaddr = memory_region_get_ram_ptr(mrs->mr) + > > + mrs->offset_within_region + > > + (xlat - mrs->offset_within_address_space); > > Are you sure you need this translation? It's done already in > address_space_translate, so it should be just > > vaddr = memory_region_get_ram_ptr(mrs->mr) + xlat;
Ah, yes. I wasn't sure what xlat was relative to (the final address space, or the final memory region). Looking more carefully at the similar path in address_space_map(), I see that it's the memory region. I'll fix that up. -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
signature.asc
Description: Digital signature