938
static int vtd_ce_get_pasid_entry(IntelIOMMUState *s, VTDContextEntry *ce,
939
VTDPASIDEntry *pe, uint32_t pasid)
940
{
941
- dma_addr_t pasid_dir_base;
941
+ dma_addr_t pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
942
943
- if (pasid == PCI_NO_PASID) {
944
- pasid = IOMMU_NO_PASID;
945
- }
946
- pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
943
return vtd_get_pe_from_pasid_table(s, pasid_dir_base, pasid, pe);
944
}
945
949
uint32_t pasid)
950
{
951
int ret;
956
- dma_addr_t pasid_dir_base;
952
+ dma_addr_t pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
953
VTDPASIDDirEntry pdire;
954
VTDPASIDEntry pe;
955
960
- if (pasid == PCI_NO_PASID) {
961
- pasid = IOMMU_NO_PASID;
962
- }
963
- pasid_dir_base = VTD_CE_GET_PASID_DIR_TABLE(ce);
964
-
956
/*
957
* No present bit check since fpd is meaningful even
958
* if the present bit is clear.
1741
*
1742
* Need to disable ir for as with PASID.
1743
*/
1753
- if (as->pasid != PCI_NO_PASID) {
1744
+ if (as->pasid != IOMMU_NO_PASID) {
1745
memory_region_set_enabled(&as->iommu_ir, false);
1746
} else {
1747
memory_region_set_enabled(&as->iommu_ir, true);
1771
* We enable per as memory region (iommu_ir_fault) for catching
1772
* the translation for interrupt range through PASID + PT.
1773
*/
1783
- if (pt && as->pasid != PCI_NO_PASID) {
1774
+ if (pt && as->pasid != IOMMU_NO_PASID) {
1775
memory_region_set_enabled(&as->iommu_ir_fault, true);
1776
} else {
1777
memory_region_set_enabled(&as->iommu_ir_fault, false);
1883
1884
VTDAddressSpace *vtd_get_as_by_sid(IntelIOMMUState *s, uint16_t sid)
1885
{
1895
- return vtd_get_as_by_sid_and_pasid(s, sid, PCI_NO_PASID);
1886
+ return vtd_get_as_by_sid_and_pasid(s, sid, IOMMU_NO_PASID);
1887
}
1888
1889
static void vtd_pt_enable_fast_path(IntelIOMMUState *s, uint16_t source_id)
2100
bool is_fpd_set = false;
2101
bool reads = true;
2102
bool writes = true;
2112
- bool is_pasid = pasid != PCI_NO_PASID;
2103
+ bool is_pasid = pasid != IOMMU_NO_PASID;
2104
uint8_t access_flags, pgtt;
2105
VTDIOTLBEntry *iotlb_entry;
2106
uint64_t xlat, size;
2113
2114
vtd_iommu_lock(s);
2115
2125
- if (pasid == PCI_NO_PASID && s->root_scalable) {
2126
- pasid = IOMMU_NO_PASID;
2127
- }
2128
-
2116
/* Try to fetch pte from IOTLB */
2117
iotlb_entry = vtd_lookup_iotlb(s, source_id, pasid, addr);
2118
if (iotlb_entry) {
2477
/*
2478
* There is no pasid field in iotlb invalidation descriptor, so IOMMU_NO_PASID
2479
* is passed as parameter. Piotlb invalidation supports pasid, pasid in its
2493
- * descriptor is passed which should not be PCI_NO_PASID.
2480
+ * descriptor is passed.
2481
*/
2482
static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
2483
uint16_t domain_id, hwaddr addr,
2491
QLIST_FOREACH(vtd_as, &(s->vtd_as_with_notifiers), next) {
2492
ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
2493
vtd_as->devfn, &ce);
2507
- if (!ret && domain_id == vtd_get_domain_id(s, &ce, vtd_as->pasid)) {
2494
+ if (ret || vtd_as->pasid != pasid ||
2495
+ domain_id != vtd_get_domain_id(s, &ce, pasid)) {
2496
+ continue;
2497
+ }
2498
+
2499
+ if (vtd_as_has_map_notifier(vtd_as)) {
2500
/*
2509
- * In legacy mode, vtd_as->pasid == pasid is always true.
2510
- * In scalable mode, for vtd address space backing a PCI
2511
- * device without pasid, needs to compare pasid with
2512
- * IOMMU_NO_PASID of this device.
2501
+ * When first stage translation is off, as long as we have MAP
2502
+ * notifications registered in any of our IOMMU notifiers,
2503
+ * we need to sync the shadow page table. Otherwise VFIO
2504
+ * device attaches to nested page table instead of shadow
2505
+ * page table, so no need to sync.
2506
*/
2514
- if (!(vtd_as->pasid == pasid ||
2515
- (vtd_as->pasid == PCI_NO_PASID && pasid == IOMMU_NO_PASID))) {
2516
- continue;
2517
- }
2518
-
2519
- if (vtd_as_has_map_notifier(vtd_as)) {
2520
- /*
2521
- * When first stage translation is off, as long as we have MAP
2522
- * notifications registered in any of our IOMMU notifiers,
2523
- * we need to sync the shadow page table. Otherwise VFIO
2524
- * device attaches to nested page table instead of shadow
2525
- * page table, so no need to sync.
2526
- */
2527
- if (!s->fsts || !s->root_scalable) {
2528
- vtd_sync_shadow_page_table_range(vtd_as, &ce, addr, size);
2529
- }
2530
- } else {
2531
- /*
2532
- * For UNMAP-only notifiers, we don't need to walk the
2533
- * page tables. We just deliver the PSI down to
2534
- * invalidate caches.
2535
- */
2536
- const IOMMUTLBEvent event = {
2537
- .type = IOMMU_NOTIFIER_UNMAP,
2538
- .entry = {
2539
- .target_as = &address_space_memory,
2540
- .iova = addr,
2541
- .translated_addr = 0,
2542
- .addr_mask = size - 1,
2543
- .perm = IOMMU_NONE,
2544
- .pasid = vtd_as->pasid,
2545
- },
2546
- };
2547
- memory_region_notify_iommu(&vtd_as->iommu, 0, event);
2507
+ if (!s->fsts || !s->root_scalable) {
2508
+ vtd_sync_shadow_page_table_range(vtd_as, &ce, addr, size);
2509
}
2510
+ } else {
2511
+ /*
2512
+ * For UNMAP-only notifiers, we don't need to walk the
2513
+ * page tables. We just deliver the PSI down to
2514
+ * invalidate caches.
2515
+ */
2516
+ const IOMMUTLBEvent event = {
2517
+ .type = IOMMU_NOTIFIER_UNMAP,
2518
+ .entry = {
2519
+ .target_as = &address_space_memory,
2520
+ .iova = addr,
2521
+ .translated_addr = 0,
2522
+ .addr_mask = size - 1,
2523
+ .perm = IOMMU_NONE,
2524
+ /* Other sub-systems use PCI pasid */
2525
+ .pasid = pasid == IOMMU_NO_PASID ? PCI_NO_PASID : pasid,
2526
+ },
2527
+ };
2528
+ memory_region_notify_iommu(&vtd_as->iommu, 0, event);
2529
}
2530
}
2531
}
2988
VTDIOTLBPageInvInfo info;
2989
VTDAddressSpace *vtd_as;
2990
VTDContextEntry ce;
2991
+ int ret;
2992
2993
info.domain_id = domain_id;
2994
info.pasid = pasid;
3001
vtd_iommu_unlock(s);
3002
3003
QLIST_FOREACH(vtd_as, &s->vtd_as_with_notifiers, next) {
3023
- if (!vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
3024
- vtd_as->devfn, &ce) &&
3025
- domain_id == vtd_get_domain_id(s, &ce, vtd_as->pasid)) {
3026
- if ((vtd_as->pasid != PCI_NO_PASID || pasid != IOMMU_NO_PASID) &&
3027
- vtd_as->pasid != pasid) {
3028
- continue;
3029
- }
3004
+ ret = vtd_dev_to_context_entry(s, pci_bus_num(vtd_as->bus),
3005
+ vtd_as->devfn, &ce);
3006
+ if (ret || vtd_as->pasid != pasid ||
3007
+ domain_id != vtd_get_domain_id(s, &ce, pasid)) {
3008
+ continue;
3009
+ }
3010
3031
- if (!s->fsts || !vtd_as_has_map_notifier(vtd_as)) {
3032
- vtd_address_space_sync(vtd_as);
3033
- }
3011
+ if (!s->fsts || !vtd_as_has_map_notifier(vtd_as)) {
3012
+ vtd_address_space_sync(vtd_as);
3013
}
3014
}
3015
}
3218
/* PASID selective implies a DID selective */
3219
trace_vtd_inv_desc_pasid_cache_psi(did, pasid);
3220
pc_info.did = did;
3242
- pc_info.pasid = pasid ?: PCI_NO_PASID;
3221
+ pc_info.pasid = pasid;
3222
break;
3223
3224
case VTD_INV_DESC_PASIDC_G_GLOBAL:
3270
* ...
3271
*/
3272
3273
+ uint32_t pasid = vtd_dev_as->pasid;
3274
IOMMUTLBEvent event;
3275
uint64_t sz;
3276
3287
event.entry.iova = addr;
3288
event.entry.perm = IOMMU_NONE;
3289
event.entry.translated_addr = 0;
3310
- event.entry.pasid = vtd_dev_as->pasid;
3290
+ /* Other sub-systems use PCI pasid */
3291
+ event.entry.pasid = pasid == IOMMU_NO_PASID ? PCI_NO_PASID : pasid;
3292
memory_region_notify_iommu(&vtd_dev_as->iommu, 0, event);
3293
}
3294
3316
sid = VTD_INV_DESC_PASID_DEVICE_IOTLB_SID(inv_desc->lo);
3317
if (global) {
3318
QLIST_FOREACH(vtd_dev_as, &s->vtd_as_with_notifiers, next) {
3338
- if ((vtd_dev_as->pasid != PCI_NO_PASID) &&
3319
+ if ((vtd_dev_as->pasid != IOMMU_NO_PASID) &&
3320
(PCI_BUILD_BDF(pci_bus_num(vtd_dev_as->bus),
3321
vtd_dev_as->devfn) == sid)) {
3322
do_invalidate_device_tlb(vtd_dev_as, size, addr);
3964
}
3965
3966
static void vtd_prepare_identity_entry(hwaddr addr, IOMMUAccessFlags perm,
3986
- uint32_t pasid, IOMMUTLBEntry *iotlb)
3967
+ IOMMUTLBEntry *iotlb)
3968
{
3969
iotlb->iova = addr & VTD_PAGE_MASK_4K;
3970
iotlb->translated_addr = addr & VTD_PAGE_MASK_4K;
3971
iotlb->addr_mask = ~VTD_PAGE_MASK_4K;
3972
iotlb->perm = perm;
3992
- iotlb->pasid = pasid;
3973
}
3974
3975
static inline void vtd_prepare_error_entry(IOMMUTLBEntry *entry)
3981
entry->pasid = PCI_NO_PASID;
3982
}
3983
3984
+/*
3985
+ * This function returns translation result to other sub-system such as PCI,
3986
+ * so iommu pasid is converted to PCI pasid and returned in IOMMUTLBEntry.
3987
+ */
3988
static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
3989
IOMMUAccessFlags flag, int iommu_idx)
3990
{
3993
IOMMUTLBEntry iotlb = {
3994
/* We'll fill in the rest later. */
3995
.target_as = &address_space_memory,
4012
- .pasid = vtd_as->pasid,
3996
+ .pasid = vtd_as->pasid == IOMMU_NO_PASID ? PCI_NO_PASID : vtd_as->pasid,
3997
};
3998
bool success;
3999
bool is_write = flag & IOMMU_WO;
4001
if (likely(s->dmar_enabled)) {
4002
/* Only support translated requests in scalable mode */
4003
if (iommu_idx == VTD_IDX_TRANSLATED && s->root_scalable) {
4020
- if (vtd_as->pasid == PCI_NO_PASID) {
4021
- vtd_prepare_identity_entry(addr, IOMMU_RW, PCI_NO_PASID,
4022
- &iotlb);
4004
+ if (vtd_as->pasid == IOMMU_NO_PASID) {
4005
+ vtd_prepare_identity_entry(addr, IOMMU_RW, &iotlb);
4006
success = true;
4007
} else {
4008
vtd_prepare_error_entry(&iotlb);
4017
}
4018
} else {
4019
/* DMAR disabled, passthrough, use 4k-page*/
4037
- vtd_prepare_identity_entry(addr, IOMMU_RW, vtd_as->pasid, &iotlb);
4020
+ vtd_prepare_identity_entry(addr, IOMMU_RW, &iotlb);
4021
success = true;
4022
}
4023
4443
}
4444
4445
vtd_report_fault(s, VTD_FR_SM_INTERRUPT_ADDR, is_fpd_set, sid, addr,
4463
- is_write, pasid != PCI_NO_PASID, pasid);
4446
+ is_write, pasid != IOMMU_NO_PASID, pasid);
4447
}
4448
4449
static void vtd_report_ir_illegal_access(VTDAddressSpace *vtd_as,
4471
int ret = 0;
4472
MSIMessage from = {}, to = {};
4473
uint16_t sid = X86_IOMMU_SID_INVALID;
4491
- uint32_t pasid;
4474
4475
from.address = (uint64_t) addr + VTD_INTERRUPT_ADDR_FIRST;
4476
from.data = (uint32_t) value;
4478
if (!attrs.unspecified) {
4479
/* We have explicit Source ID */
4480
sid = attrs.requester_id;
4499
- pasid = attrs.pid != 0 ? attrs.pid : PCI_NO_PASID;
4481
4482
if (attrs.address_type == PCI_AT_TRANSLATED &&
4483
sid != X86_IOMMU_SID_INVALID) {
4503
- vtd_report_sid_ir_illegal_access(s, sid, pasid, from.address, true);
4484
+ vtd_report_sid_ir_illegal_access(s, sid, attrs.pid, from.address,
4485
+ true);
4486
return MEMTX_ERROR;
4487
}
4488
}
4544
},
4545
};
4546
4547
+/*
4548
+ * This function is called by many PCIIOMMUOps callbacks to get
4549
+ * VTDAddressSpace or create one if non-exist. Those callbacks are
4550
+ * used by PCI sub-system and are passed in a PCI pasid value.
4551
+ *
4552
+ * VTD honors iommu pasid, so the first thing is to convert PCI
4553
+ * pasid to iommu pasid.
4554
+ */
4555
VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus,
4556
int devfn, unsigned int pasid)
4557
{
4558
+ pasid = pasid == PCI_NO_PASID ? IOMMU_NO_PASID : pasid;
4559
+
4560
/*
4561
* We can't simply use sid here since the bus number might not be
4562
* initialized by the guest.
4598
new_key->devfn = devfn;
4599
new_key->pasid = pasid;
4600
4609
- if (pasid == PCI_NO_PASID) {
4601
+ if (pasid == IOMMU_NO_PASID) {
4602
snprintf(name, sizeof(name), "vtd-%02x.%x", PCI_SLOT(devfn),
4603
PCI_FUNC(devfn));
4604
} else {
5282
vtd_ce_get_pasid_fpd(s, &ce, &is_fpd_set, vtd_as->pasid);
5283
error_report:
5284
vtd_report_fault(s, -ret, is_fpd_set, sid, addr, is_write,
5293
- vtd_as->pasid != PCI_NO_PASID, vtd_as->pasid);
5285
+ vtd_as->pasid != IOMMU_NO_PASID, vtd_as->pasid);
5286
return false;
5287
}
5288
5373
*/
5374
5375
/* We do not support PRI without PASID */
5384
- if (vtd_as->pasid == PCI_NO_PASID) {
5376
+ if (vtd_as->pasid == IOMMU_NO_PASID) {
5377
return -EPERM;
5378
}
5379
if (exec_req && !is_read) {