>-----Original Message-----
>From: Liu, Yi L <[email protected]>
>Subject: Re: [PATCH 1/3] intel_iommu: Handle PASID cache invalidation
>
>On 2025/10/15 18:20, Zhenzhong Duan wrote:
>> Adds an new entry VTDPASIDCacheEntry in VTDAddressSpace to cache the
>pasid
>> entry and track PASID usage and future PASID tagged DMA address
>translation
>> support in vIOMMU.
>>
>> When guest triggers pasid cache invalidation, QEMU will capture it and
>> update or invalidate pasid cache.
>>
>> vIOMMU emulator could figure out the reason by fetching latest guest pasid
>> entry in memory and compare it with cached PASID entry if it's valid.
>>
>> Signed-off-by: Yi Liu <[email protected]>
>> Signed-off-by: Zhenzhong Duan <[email protected]>
>> ---
>>   hw/i386/intel_iommu_internal.h |  19 ++++-
>>   include/hw/i386/intel_iommu.h  |   6 ++
>>   hw/i386/intel_iommu.c          | 150
>++++++++++++++++++++++++++++++---
>>   hw/i386/trace-events           |   3 +
>>   4 files changed, 165 insertions(+), 13 deletions(-)
>>
>> diff --git a/hw/i386/intel_iommu_internal.h
>b/hw/i386/intel_iommu_internal.h
>> index 0f6a1237e4..80193ff28b 100644
>> --- a/hw/i386/intel_iommu_internal.h
>> +++ b/hw/i386/intel_iommu_internal.h
>> @@ -316,6 +316,8 @@ typedef enum VTDFaultReason {
>>                                     * request while disabled */
>>       VTD_FR_IR_SID_ERR = 0x26,   /* Invalid Source-ID */
>>
>> +    VTD_FR_RTADDR_INV_TTM = 0x31,  /* Invalid TTM in RTADDR */
>> +
>>       VTD_FR_SM_PRE_ABS = 0x47,   /* SCT.8 : PRE bit in a present SM
>CE is 0 */
>>
>>       /* PASID directory entry access failure */
>> @@ -517,6 +519,15 @@ typedef union VTDPRDesc VTDPRDesc;
>>   #define VTD_INV_DESC_PIOTLB_RSVD_VAL0
>0xfff000000000f1c0ULL
>>   #define VTD_INV_DESC_PIOTLB_RSVD_VAL1     0xf80ULL
>>
>> +/* PASID-cache Invalidate Descriptor (pc_inv_dsc) fields */
>> +#define VTD_INV_DESC_PASIDC_G(x)        extract64((x)->val[0], 4, 2)
>> +#define VTD_INV_DESC_PASIDC_G_DSI       0
>> +#define VTD_INV_DESC_PASIDC_G_PASID_SI  1
>> +#define VTD_INV_DESC_PASIDC_G_GLOBAL    3
>> +#define VTD_INV_DESC_PASIDC_DID(x)      extract64((x)->val[0], 16,
>16)
>> +#define VTD_INV_DESC_PASIDC_PASID(x)    extract64((x)->val[0], 32,
>20)
>> +#define VTD_INV_DESC_PASIDC_RSVD_VAL0   0xfff000000000f1c0ULL
>> +
>>   /* Page Request Descriptor */
>>   /* For the low 64-bit of 128-bit */
>>   #define VTD_PRD_TYPE            (1ULL)
>> @@ -603,6 +614,12 @@ typedef struct VTDRootEntry VTDRootEntry;
>>   #define VTD_SM_CONTEXT_ENTRY_RSVD_VAL1
>0xffffffffffe00000ULL
>>   #define VTD_SM_CONTEXT_ENTRY_PRE            0x10ULL
>>
>> +typedef struct VTDPASIDCacheInfo {
>> +    uint8_t type;
>> +    uint16_t did;
>> +    uint32_t pasid;
>> +} VTDPASIDCacheInfo;
>> +
>>   /* PASID Table Related Definitions */
>>   #define VTD_PASID_DIR_BASE_ADDR_MASK  (~0xfffULL)
>>   #define VTD_PASID_TABLE_BASE_ADDR_MASK (~0xfffULL)
>> @@ -624,7 +641,7 @@ typedef struct VTDRootEntry VTDRootEntry;
>>   #define VTD_SM_PASID_ENTRY_PT          (4ULL << 6)
>>
>>   #define VTD_SM_PASID_ENTRY_AW          7ULL /* Adjusted
>guest-address-width */
>> -#define VTD_SM_PASID_ENTRY_DID(val)    ((val) &
>VTD_DOMAIN_ID_MASK)
>> +#define VTD_SM_PASID_ENTRY_DID(x)      extract64((x)->val[1], 0, 16)
>
>I think this can be done in a separate patch.

OK, nesting series has a patch handling this kind of cleanup, will move it 
there.

>
>>
>>   #define VTD_SM_PASID_ENTRY_FLPM          3ULL
>>   #define VTD_SM_PASID_ENTRY_FLPTPTR       (~0xfffULL)
>> diff --git a/include/hw/i386/intel_iommu.h
>b/include/hw/i386/intel_iommu.h
>> index 47730ac3c7..6e68734b3c 100644
>> --- a/include/hw/i386/intel_iommu.h
>> +++ b/include/hw/i386/intel_iommu.h
>> @@ -95,6 +95,11 @@ struct VTDPASIDEntry {
>>       uint64_t val[8];
>>   };
>>
>> +typedef struct VTDPASIDCacheEntry {
>> +    struct VTDPASIDEntry pasid_entry;
>> +    bool valid;
>> +} VTDPASIDCacheEntry;
>> +
>>   struct VTDAddressSpace {
>>       PCIBus *bus;
>>       uint8_t devfn;
>> @@ -107,6 +112,7 @@ struct VTDAddressSpace {
>>       MemoryRegion iommu_ir_fault; /* Interrupt region for catching
>fault */
>>       IntelIOMMUState *iommu_state;
>>       VTDContextCacheEntry context_cache_entry;
>> +    VTDPASIDCacheEntry pasid_cache_entry;
>>       QLIST_ENTRY(VTDAddressSpace) next;
>>       /* Superset of notifier flags that this address space has */
>>       IOMMUNotifierFlag notifier_flags;
>> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
>> index 6a168d5107..66f45f89cb 100644
>> --- a/hw/i386/intel_iommu.c
>> +++ b/hw/i386/intel_iommu.c
>> @@ -1607,7 +1607,7 @@ static uint16_t
>vtd_get_domain_id(IntelIOMMUState *s,
>>
>>       if (s->root_scalable) {
>>           vtd_ce_get_rid2pasid_entry(s, ce, &pe, pasid);
>> -        return VTD_SM_PASID_ENTRY_DID(pe.val[1]);
>> +        return VTD_SM_PASID_ENTRY_DID(&pe);
>>       }
>>
>>       return VTD_CONTEXT_ENTRY_DID(ce->hi);
>> @@ -3051,6 +3051,135 @@ static bool
>vtd_process_piotlb_desc(IntelIOMMUState *s,
>>       return true;
>>   }
>>
>> +static inline int vtd_dev_get_pe_from_pasid(VTDAddressSpace *vtd_as,
>> +                                            VTDPASIDEntry *pe)
>> +{
>> +    IntelIOMMUState *s = vtd_as->iommu_state;
>> +    VTDContextEntry ce;
>> +    int ret;
>> +
>> +    if (!s->root_scalable) {
>> +        return -VTD_FR_RTADDR_INV_TTM;
>> +    }
>> +
>> +    ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
>vtd_as->devfn,
>> +                                   &ce);
>> +    if (ret) {
>> +        return ret;
>> +    }
>> +
>> +    return vtd_ce_get_rid2pasid_entry(s, &ce, pe, vtd_as->pasid);
>> +}
>> +
>> +/*
>> + * Update or invalidate pasid cache based on the value in memory.
>
>s/the value in memory./the pasid entry in guest memory.

OK

>
>> + */
>> +static void vtd_pasid_cache_sync_locked(gpointer key, gpointer value,
>> +                                        gpointer user_data)
>> +{
>> +    VTDPASIDCacheInfo *pc_info = user_data;
>> +    VTDAddressSpace *vtd_as = value;
>> +    VTDPASIDCacheEntry *pc_entry = &vtd_as->pasid_cache_entry;
>> +    VTDPASIDEntry pe;
>> +    uint16_t did;
>> +
>> +    if (vtd_dev_get_pe_from_pasid(vtd_as, &pe)) {
>> +        /*
>> +         * 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;
>> +        return;
>> +    }
>> +
>> +    /*
>> +     * VTD_INV_DESC_PASIDC_G_DSI and
>VTD_INV_DESC_PASIDC_G_PASID_SI require
>> +     * DID check. If DID doesn't match the value in cache or memory,
>then
>> +     * it's not a pasid entry we want to invalidate.
>> +     */
>> +    switch (pc_info->type) {
>> +    case VTD_INV_DESC_PASIDC_G_PASID_SI:
>> +        if (pc_info->pasid != vtd_as->pasid) {
>> +            return;
>> +        }
>> +        /* Fall through */
>> +    case VTD_INV_DESC_PASIDC_G_DSI:
>> +        if (pc_entry->valid) {
>> +            did = VTD_SM_PASID_ENTRY_DID(&pc_entry->pasid_entry);
>> +            if (pc_info->did == did) {
>> +                break;
>> +            }
>> +        }
>> +        did = VTD_SM_PASID_ENTRY_DID(&pe);
>> +        if (pc_info->did == did) {
>> +            break;
>> +        }
>
>hmmm. how about below?
>
>         /*
>          * For newly set pasid entry, iommu driver is supposed to
>          * invalidate pasid cache with the did configed in pasid entry
>          * when caching-mode is reported. Oherwise qemu vIOMMU just
>skip
>          * it.
>          */
>         if pc_entry->valid) {
>             did = VTD_SM_PASID_ENTRY_DID(&pc_entry->pasid_entry);
>         } else {
>             did = VTD_SM_PASID_ENTRY_DID(&pe);
>         }
>
>         if (pc_info->did != did) {
>             return;
>         }

Yes, looks cleaner, will do.

Thanks
Zhenzhong

Reply via email to