>-----Original Message-----
>From: Liu, Yi L <[email protected]>
>Subject: Re: [PATCH v3 3/3] intel_iommu: Fix DMA failure when guest
>switches IOMMU domain
>
>On 2025/10/17 17:36, Zhenzhong Duan wrote:
>> Kernel allows user to switch IOMMU domain, e.g., switch between DMA
>> and identity domain. When this happen in IOMMU scalable mode, a pasid
>> cache invalidation request is sent, this request is ignored by vIOMMU
>> which leads to device binding to wrong address space, then DMA fails.
>>
>> This issue exists in scalable mode with both first stage and second
>> stage translations, both emulated and passthrough devices.
>>
>> Take network device for example, below sequence trigger issue:
>>
>> 1. start a guest with iommu=pt
>> 2. echo 0000:01:00.0 > /sys/bus/pci/drivers/virtio-pci/unbind
>> 3. echo DMA > /sys/kernel/iommu_groups/6/type
>> 4. echo 0000:01:00.0 > /sys/bus/pci/drivers/virtio-pci/bind
>> 5. Ping test
>>
>> Fix it by switching address space in invalidation handler.
>>
>> Fixes: 4a4f219e8a10 ("intel_iommu: add scalable-mode option to make
>scalable mode work")
>> Signed-off-by: Zhenzhong Duan <[email protected]>
>> ---
>>   hw/i386/intel_iommu.c | 29 +++++++++++++++++++++++++++--
>>   1 file changed, 27 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
>> index 07bc0a749c..c402643b56 100644
>> --- a/hw/i386/intel_iommu.c
>> +++ b/hw/i386/intel_iommu.c
>> @@ -3087,6 +3087,11 @@ static inline int
>vtd_dev_get_pe_from_pasid(VTDAddressSpace *vtd_as,
>>       return vtd_ce_get_rid2pasid_entry(s, &ce, pe, vtd_as->pasid);
>>   }
>>
>> +static int vtd_pasid_entry_compare(VTDPASIDEntry *p1, VTDPASIDEntry
>*p2)
>> +{
>> +    return memcmp(p1, p2, sizeof(*p1));
>> +}
>> +
>>   /* Update or invalidate pasid cache based on the pasid entry in guest
>memory. */
>>   static void vtd_pasid_cache_sync_locked(gpointer key, gpointer value,
>>                                           gpointer user_data)
>> @@ -3095,15 +3100,28 @@ static void
>vtd_pasid_cache_sync_locked(gpointer key, gpointer value,
>>       VTDAddressSpace *vtd_as = value;
>>       VTDPASIDCacheEntry *pc_entry = &vtd_as->pasid_cache_entry;
>>       VTDPASIDEntry pe;
>> +    IOMMUNotifier *n;
>>       uint16_t did;
>>
>>       if (vtd_dev_get_pe_from_pasid(vtd_as, &pe)) {
>> +        if (!pc_entry->valid) {
>> +            return;
>> +        }
>>           /*
>>            * No valid pasid entry in guest memory. e.g. pasid entry was
>modified
>>            * to be either all-zero or non-present. Either case means
>existing
>>            * pasid cache should be invalidated.
>>            */
>>           pc_entry->valid = false;
>> +
>> +        /*
>> +         * When a pasid entry isn't valid any more, we should unmap all
>> +         * mappings in shadow pages instantly to ensure DMA security.
>> +         */
>> +        IOMMU_NOTIFIER_FOREACH(n, &vtd_as->iommu) {
>> +            vtd_address_space_unmap(vtd_as, n);
>> +        }
>
>I just realized that if the MR is nodmar MR, the notifier is not
>registered at all. is it? So the above loop and below does not
>duplicate.

Yes, iommu notifier is a mechanism only for iommu MR.

Thanks
Zhenzhong

Reply via email to