Message ID | 20240718081636.879544-11-zhenzhong.duan@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | intel_iommu: Enable stage-1 translation for emulated device | expand |
Reviewed-by: Clément Mathieu--Drif<clement.mathieu--drif@eviden.com> On 18/07/2024 10:16, Zhenzhong Duan wrote: > Caution: External email. Do not open attachments or click links, unless this email comes from a known sender and you know the content is safe. > > > PASID-based iotlb (piotlb) is used during walking Intel > VT-d stage-1 page table. > > This emulates the stage-1 page table iotlb invalidation requested > by a PASID-based IOTLB Invalidate Descriptor (P_IOTLB). > > Signed-off-by: Yi Liu <yi.l.liu@intel.com> > Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com> > --- > hw/i386/intel_iommu_internal.h | 3 +++ > hw/i386/intel_iommu.c | 45 ++++++++++++++++++++++++++++++++++ > 2 files changed, 48 insertions(+) > > diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h > index cf0f176e06..7dd8176e86 100644 > --- a/hw/i386/intel_iommu_internal.h > +++ b/hw/i386/intel_iommu_internal.h > @@ -470,6 +470,9 @@ typedef union VTDInvDesc VTDInvDesc; > #define VTD_INV_DESC_PIOTLB_PASID(val) (((val) >> 32) & 0xfffffULL) > #define VTD_INV_DESC_PIOTLB_DID(val) (((val) >> 16) & \ > VTD_DOMAIN_ID_MASK) > +#define VTD_INV_DESC_PIOTLB_ADDR(val) ((val) & ~0xfffULL) > +#define VTD_INV_DESC_PIOTLB_AM(val) ((val) & 0x3fULL) > +#define VTD_INV_DESC_PIOTLB_IH(val) (((val) >> 6) & 0x1) > > /* Information about page-selective IOTLB invalidate */ > struct VTDIOTLBPageInvInfo { > diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c > index 8d47e5ba78..8ebb6dbd7d 100644 > --- a/hw/i386/intel_iommu.c > +++ b/hw/i386/intel_iommu.c > @@ -322,6 +322,28 @@ static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value, > return (entry->gfn & info->mask) == gfn || entry->gfn == gfn_tlb; > } > > +static gboolean vtd_hash_remove_by_page_piotlb(gpointer key, gpointer value, > + gpointer user_data) > +{ > + VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value; > + VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data; > + uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask; > + uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K; > + > + /* > + * According to spec, PASID-based-IOTLB Invalidation in page granularity > + * doesn't invalidate IOTLB entries caching second-stage (PGTT=010b) > + * or pass-through (PGTT=100b) mappings. Nested isn't supported yet, > + * so only need to check first-stage (PGTT=001b) mappings. > + */ > + if (entry->pgtt != VTD_SM_PASID_ENTRY_FLT) { > + return false; > + } > + > + return entry->domain_id == info->domain_id && entry->pasid == info->pasid && > + ((entry->gfn & info->mask) == gfn || entry->gfn == gfn_tlb); > +} > + > /* Reset all the gen of VTDAddressSpace to zero and set the gen of > * IntelIOMMUState to 1. Must be called with IOMMU lock held. > */ > @@ -2886,11 +2908,30 @@ static void vtd_piotlb_pasid_invalidate(IntelIOMMUState *s, > } > } > > +static void vtd_piotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id, > + uint32_t pasid, hwaddr addr, uint8_t am, > + bool ih) > +{ > + VTDIOTLBPageInvInfo info; > + > + info.domain_id = domain_id; > + info.pasid = pasid; > + info.addr = addr; > + info.mask = ~((1 << am) - 1); > + > + vtd_iommu_lock(s); > + g_hash_table_foreach_remove(s->iotlb, > + vtd_hash_remove_by_page_piotlb, &info); > + vtd_iommu_unlock(s); > +} > + > static bool vtd_process_piotlb_desc(IntelIOMMUState *s, > VTDInvDesc *inv_desc) > { > uint16_t domain_id; > uint32_t pasid; > + uint8_t am; > + hwaddr addr; > > if ((inv_desc->val[0] & VTD_INV_DESC_PIOTLB_RSVD_VAL0) || > (inv_desc->val[1] & VTD_INV_DESC_PIOTLB_RSVD_VAL1)) { > @@ -2907,6 +2948,10 @@ static bool vtd_process_piotlb_desc(IntelIOMMUState *s, > break; > > case VTD_INV_DESC_PIOTLB_PSI_IN_PASID: > + am = VTD_INV_DESC_PIOTLB_AM(inv_desc->val[1]); > + addr = (hwaddr) VTD_INV_DESC_PIOTLB_ADDR(inv_desc->val[1]); > + vtd_piotlb_page_invalidate(s, domain_id, pasid, addr, am, > + VTD_INV_DESC_PIOTLB_IH(inv_desc->val[1])); > break; > > default: > -- > 2.34.1 >
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index cf0f176e06..7dd8176e86 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -470,6 +470,9 @@ typedef union VTDInvDesc VTDInvDesc; #define VTD_INV_DESC_PIOTLB_PASID(val) (((val) >> 32) & 0xfffffULL) #define VTD_INV_DESC_PIOTLB_DID(val) (((val) >> 16) & \ VTD_DOMAIN_ID_MASK) +#define VTD_INV_DESC_PIOTLB_ADDR(val) ((val) & ~0xfffULL) +#define VTD_INV_DESC_PIOTLB_AM(val) ((val) & 0x3fULL) +#define VTD_INV_DESC_PIOTLB_IH(val) (((val) >> 6) & 0x1) /* Information about page-selective IOTLB invalidate */ struct VTDIOTLBPageInvInfo { diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 8d47e5ba78..8ebb6dbd7d 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -322,6 +322,28 @@ static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value, return (entry->gfn & info->mask) == gfn || entry->gfn == gfn_tlb; } +static gboolean vtd_hash_remove_by_page_piotlb(gpointer key, gpointer value, + gpointer user_data) +{ + VTDIOTLBEntry *entry = (VTDIOTLBEntry *)value; + VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data; + uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask; + uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K; + + /* + * According to spec, PASID-based-IOTLB Invalidation in page granularity + * doesn't invalidate IOTLB entries caching second-stage (PGTT=010b) + * or pass-through (PGTT=100b) mappings. Nested isn't supported yet, + * so only need to check first-stage (PGTT=001b) mappings. + */ + if (entry->pgtt != VTD_SM_PASID_ENTRY_FLT) { + return false; + } + + return entry->domain_id == info->domain_id && entry->pasid == info->pasid && + ((entry->gfn & info->mask) == gfn || entry->gfn == gfn_tlb); +} + /* Reset all the gen of VTDAddressSpace to zero and set the gen of * IntelIOMMUState to 1. Must be called with IOMMU lock held. */ @@ -2886,11 +2908,30 @@ static void vtd_piotlb_pasid_invalidate(IntelIOMMUState *s, } } +static void vtd_piotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id, + uint32_t pasid, hwaddr addr, uint8_t am, + bool ih) +{ + VTDIOTLBPageInvInfo info; + + info.domain_id = domain_id; + info.pasid = pasid; + info.addr = addr; + info.mask = ~((1 << am) - 1); + + vtd_iommu_lock(s); + g_hash_table_foreach_remove(s->iotlb, + vtd_hash_remove_by_page_piotlb, &info); + vtd_iommu_unlock(s); +} + static bool vtd_process_piotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) { uint16_t domain_id; uint32_t pasid; + uint8_t am; + hwaddr addr; if ((inv_desc->val[0] & VTD_INV_DESC_PIOTLB_RSVD_VAL0) || (inv_desc->val[1] & VTD_INV_DESC_PIOTLB_RSVD_VAL1)) { @@ -2907,6 +2948,10 @@ static bool vtd_process_piotlb_desc(IntelIOMMUState *s, break; case VTD_INV_DESC_PIOTLB_PSI_IN_PASID: + am = VTD_INV_DESC_PIOTLB_AM(inv_desc->val[1]); + addr = (hwaddr) VTD_INV_DESC_PIOTLB_ADDR(inv_desc->val[1]); + vtd_piotlb_page_invalidate(s, domain_id, pasid, addr, am, + VTD_INV_DESC_PIOTLB_IH(inv_desc->val[1])); break; default: