intel_iommu: handle invalid ce for shadow sync
We should handle VTD_FR_CONTEXT_ENTRY_P properly when synchronizing shadow page tables. Having invalid context entry there is perfectly valid when we move a device out of an existing domain. When that happens, instead of posting an error we invalidate the whole region. Without this patch, QEMU will crash if we do these steps: (1) start QEMU with VT-d IOMMU and two 10G NICs (ixgbe) (2) bind the NICs with vfio-pci in the guest (3) start testpmd with the NICs applied (4) stop testpmd (5) rebind the NIC back to ixgbe kernel driver The patch should fix it. Reported-by: Pei Zhang <pezhang@redhat.com> Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1627272 Signed-off-by: Peter Xu <peterx@redhat.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
		
							parent
							
								
									95ecd3df78
								
							
						
					
					
						commit
						c28b535d08
					
				@ -38,6 +38,7 @@
 | 
				
			|||||||
#include "trace.h"
 | 
					#include "trace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void vtd_address_space_refresh_all(IntelIOMMUState *s);
 | 
					static void vtd_address_space_refresh_all(IntelIOMMUState *s);
 | 
				
			||||||
 | 
					static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val,
 | 
					static void vtd_define_quad(IntelIOMMUState *s, hwaddr addr, uint64_t val,
 | 
				
			||||||
                            uint64_t wmask, uint64_t w1cmask)
 | 
					                            uint64_t wmask, uint64_t w1cmask)
 | 
				
			||||||
@ -1066,11 +1067,27 @@ static int vtd_sync_shadow_page_table(VTDAddressSpace *vtd_as)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    VTDContextEntry ce;
 | 
					    VTDContextEntry ce;
 | 
				
			||||||
 | 
					    IOMMUNotifier *n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = vtd_dev_to_context_entry(vtd_as->iommu_state,
 | 
					    ret = vtd_dev_to_context_entry(vtd_as->iommu_state,
 | 
				
			||||||
                                   pci_bus_num(vtd_as->bus),
 | 
					                                   pci_bus_num(vtd_as->bus),
 | 
				
			||||||
                                   vtd_as->devfn, &ce);
 | 
					                                   vtd_as->devfn, &ce);
 | 
				
			||||||
    if (ret) {
 | 
					    if (ret) {
 | 
				
			||||||
 | 
					        if (ret == -VTD_FR_CONTEXT_ENTRY_P) {
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					             * It's a valid scenario to have a context entry that is
 | 
				
			||||||
 | 
					             * not present.  For example, when a device is removed
 | 
				
			||||||
 | 
					             * from an existing domain then the context entry will be
 | 
				
			||||||
 | 
					             * zeroed by the guest before it was put into another
 | 
				
			||||||
 | 
					             * domain.  When this happens, instead of synchronizing
 | 
				
			||||||
 | 
					             * the shadow pages we should invalidate all existing
 | 
				
			||||||
 | 
					             * mappings and notify the backends.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            IOMMU_NOTIFIER_FOREACH(n, &vtd_as->iommu) {
 | 
				
			||||||
 | 
					                vtd_address_space_unmap(vtd_as, n);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ret = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return ret;
 | 
					        return ret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user