|
@@ -305,9 +305,21 @@ static gboolean vtd_hash_remove_by_page(gpointer key, gpointer value,
|
|
VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
|
|
VTDIOTLBPageInvInfo *info = (VTDIOTLBPageInvInfo *)user_data;
|
|
uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask;
|
|
uint64_t gfn = (info->addr >> VTD_PAGE_SHIFT_4K) & info->mask;
|
|
uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K;
|
|
uint64_t gfn_tlb = (info->addr & entry->mask) >> VTD_PAGE_SHIFT_4K;
|
|
- return (entry->domain_id == info->domain_id) &&
|
|
|
|
- (((entry->gfn & info->mask) == gfn) ||
|
|
|
|
- (entry->gfn == gfn_tlb));
|
|
|
|
|
|
+
|
|
|
|
+ if (entry->domain_id != info->domain_id) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * According to spec, IOTLB entries caching first-stage (PGTT=001b) or
|
|
|
|
+ * nested (PGTT=011b) mapping associated with specified domain-id are
|
|
|
|
+ * invalidated. Nested isn't supported yet, so only need to check 001b.
|
|
|
|
+ */
|
|
|
|
+ if (entry->pgtt == VTD_SM_PASID_ENTRY_FLT) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (entry->gfn & info->mask) == gfn || entry->gfn == gfn_tlb;
|
|
}
|
|
}
|
|
|
|
|
|
/* Reset all the gen of VTDAddressSpace to zero and set the gen of
|
|
/* Reset all the gen of VTDAddressSpace to zero and set the gen of
|
|
@@ -382,7 +394,7 @@ out:
|
|
static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
|
static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
|
uint16_t domain_id, hwaddr addr, uint64_t pte,
|
|
uint16_t domain_id, hwaddr addr, uint64_t pte,
|
|
uint8_t access_flags, uint32_t level,
|
|
uint8_t access_flags, uint32_t level,
|
|
- uint32_t pasid)
|
|
|
|
|
|
+ uint32_t pasid, uint8_t pgtt)
|
|
{
|
|
{
|
|
VTDIOTLBEntry *entry = g_malloc(sizeof(*entry));
|
|
VTDIOTLBEntry *entry = g_malloc(sizeof(*entry));
|
|
struct vtd_iotlb_key *key = g_malloc(sizeof(*key));
|
|
struct vtd_iotlb_key *key = g_malloc(sizeof(*key));
|
|
@@ -400,6 +412,7 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
|
|
entry->access_flags = access_flags;
|
|
entry->access_flags = access_flags;
|
|
entry->mask = vtd_pt_level_page_mask(level);
|
|
entry->mask = vtd_pt_level_page_mask(level);
|
|
entry->pasid = pasid;
|
|
entry->pasid = pasid;
|
|
|
|
+ entry->pgtt = pgtt;
|
|
|
|
|
|
key->gfn = gfn;
|
|
key->gfn = gfn;
|
|
key->sid = source_id;
|
|
key->sid = source_id;
|
|
@@ -2062,7 +2075,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
|
bool is_fpd_set = false;
|
|
bool is_fpd_set = false;
|
|
bool reads = true;
|
|
bool reads = true;
|
|
bool writes = true;
|
|
bool writes = true;
|
|
- uint8_t access_flags;
|
|
|
|
|
|
+ uint8_t access_flags, pgtt;
|
|
bool rid2pasid = (pasid == PCI_NO_PASID) && s->root_scalable;
|
|
bool rid2pasid = (pasid == PCI_NO_PASID) && s->root_scalable;
|
|
VTDIOTLBEntry *iotlb_entry;
|
|
VTDIOTLBEntry *iotlb_entry;
|
|
uint64_t xlat, size;
|
|
uint64_t xlat, size;
|
|
@@ -2171,9 +2184,11 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
|
if (s->flts && s->root_scalable) {
|
|
if (s->flts && s->root_scalable) {
|
|
ret_fr = vtd_iova_to_flpte(s, &ce, addr, is_write, &pte, &level,
|
|
ret_fr = vtd_iova_to_flpte(s, &ce, addr, is_write, &pte, &level,
|
|
&reads, &writes, s->aw_bits, pasid);
|
|
&reads, &writes, s->aw_bits, pasid);
|
|
|
|
+ pgtt = VTD_SM_PASID_ENTRY_FLT;
|
|
} else {
|
|
} else {
|
|
ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &pte, &level,
|
|
ret_fr = vtd_iova_to_slpte(s, &ce, addr, is_write, &pte, &level,
|
|
&reads, &writes, s->aw_bits, pasid);
|
|
&reads, &writes, s->aw_bits, pasid);
|
|
|
|
+ pgtt = VTD_SM_PASID_ENTRY_SLT;
|
|
}
|
|
}
|
|
if (!ret_fr) {
|
|
if (!ret_fr) {
|
|
xlat = vtd_get_pte_addr(pte, s->aw_bits);
|
|
xlat = vtd_get_pte_addr(pte, s->aw_bits);
|
|
@@ -2207,7 +2222,7 @@ static bool vtd_do_iommu_translate(VTDAddressSpace *vtd_as, PCIBus *bus,
|
|
page_mask = vtd_pt_level_page_mask(level);
|
|
page_mask = vtd_pt_level_page_mask(level);
|
|
access_flags = IOMMU_ACCESS_FLAG(reads, writes);
|
|
access_flags = IOMMU_ACCESS_FLAG(reads, writes);
|
|
vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce, pasid),
|
|
vtd_update_iotlb(s, source_id, vtd_get_domain_id(s, &ce, pasid),
|
|
- addr, pte, access_flags, level, pasid);
|
|
|
|
|
|
+ addr, pte, access_flags, level, pasid, pgtt);
|
|
out:
|
|
out:
|
|
vtd_iommu_unlock(s);
|
|
vtd_iommu_unlock(s);
|
|
entry->iova = addr & page_mask;
|
|
entry->iova = addr & page_mask;
|