|
@@ -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:
|