intel_iommu: Process PASID-based iotlb invalidation

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>
Reviewed-by: Clément Mathieu--Drif<clement.mathieu--drif@eviden.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Reviewed-by: Yi Liu <yi.l.liu@intel.com>
Message-Id: <20241212083757.605022-12-zhenzhong.duan@intel.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Zhenzhong Duan 2024-12-12 16:37:48 +08:00 committed by Michael S. Tsirkin
parent 16d4e418e9
commit 6ebe6cf2a0
2 changed files with 46 additions and 0 deletions

View file

@ -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.
*/
@ -2937,11 +2959,29 @@ 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)
{
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;
hwaddr addr;
uint8_t am;
uint64_t mask[4] = {VTD_INV_DESC_PIOTLB_RSVD_VAL0,
VTD_INV_DESC_PIOTLB_RSVD_VAL1,
VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
@ -2959,6 +2999,9 @@ 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);
break;
default:

View file

@ -471,6 +471,9 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_PIOTLB_PSI_IN_PASID (3ULL << 4)
#define VTD_INV_DESC_PIOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
#define VTD_INV_DESC_PIOTLB_PASID(val) (((val) >> 32) & 0xfffffULL)
#define VTD_INV_DESC_PIOTLB_AM(val) ((val) & 0x3fULL)
#define VTD_INV_DESC_PIOTLB_IH(val) (((val) >> 6) & 0x1)
#define VTD_INV_DESC_PIOTLB_ADDR(val) ((val) & ~0xfffULL)
#define VTD_INV_DESC_PIOTLB_RSVD_VAL0 0xfff000000000f1c0ULL
#define VTD_INV_DESC_PIOTLB_RSVD_VAL1 0xf80ULL