Skip to content

Commit

Permalink
memory: Add IOMMUTLBEvent
Browse files Browse the repository at this point in the history
This way we can tell between regular IOMMUTLBEntry (entry of IOMMU
hardware) and notifications.

In the notifications, we set explicitly if it is a MAPs or an UNMAP,
instead of trusting in entry permissions to differentiate them.

Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Message-Id: <20201116165506.31315-3-eperezma@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Acked-by: David Gibson <david@gibson.dropbear.id.au>
  • Loading branch information
eugpermar authored and mstsirkin committed Dec 8, 2020
1 parent 3b5ebf8 commit 5039caf
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 122 deletions.
13 changes: 7 additions & 6 deletions hw/arm/smmu-common.c
Expand Up @@ -465,14 +465,15 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid)
/* Unmap the whole notifier's range */
static void smmu_unmap_notifier_range(IOMMUNotifier *n)
{
IOMMUTLBEntry entry;
IOMMUTLBEvent event;

entry.target_as = &address_space_memory;
entry.iova = n->start;
entry.perm = IOMMU_NONE;
entry.addr_mask = n->end - n->start;
event.type = IOMMU_NOTIFIER_UNMAP;
event.entry.target_as = &address_space_memory;
event.entry.iova = n->start;
event.entry.perm = IOMMU_NONE;
event.entry.addr_mask = n->end - n->start;

memory_region_notify_iommu_one(n, &entry);
memory_region_notify_iommu_one(n, &event);
}

/* Unmap all notifiers attached to @mr */
Expand Down
13 changes: 7 additions & 6 deletions hw/arm/smmuv3.c
Expand Up @@ -800,7 +800,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
uint8_t tg, uint64_t num_pages)
{
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
IOMMUTLBEntry entry;
IOMMUTLBEvent event;
uint8_t granule = tg;

if (!tg) {
Expand All @@ -823,12 +823,13 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
granule = tt->granule_sz;
}

entry.target_as = &address_space_memory;
entry.iova = iova;
entry.addr_mask = num_pages * (1 << granule) - 1;
entry.perm = IOMMU_NONE;
event.type = IOMMU_NOTIFIER_UNMAP;
event.entry.target_as = &address_space_memory;
event.entry.iova = iova;
event.entry.addr_mask = num_pages * (1 << granule) - 1;
event.entry.perm = IOMMU_NONE;

memory_region_notify_iommu_one(n, &entry);
memory_region_notify_iommu_one(n, &event);
}

/* invalidate an asid/iova range tuple in all mr's */
Expand Down
88 changes: 49 additions & 39 deletions hw/i386/intel_iommu.c
Expand Up @@ -1073,7 +1073,7 @@ static int vtd_iova_to_slpte(IntelIOMMUState *s, VTDContextEntry *ce,
}
}

typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private);
typedef int (*vtd_page_walk_hook)(IOMMUTLBEvent *event, void *private);

/**
* Constant information used during page walking
Expand All @@ -1094,11 +1094,12 @@ typedef struct {
uint16_t domain_id;
} vtd_page_walk_info;

static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info)
static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info)
{
VTDAddressSpace *as = info->as;
vtd_page_walk_hook hook_fn = info->hook_fn;
void *private = info->private;
IOMMUTLBEntry *entry = &event->entry;
DMAMap target = {
.iova = entry->iova,
.size = entry->addr_mask,
Expand All @@ -1107,15 +1108,15 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info)
};
DMAMap *mapped = iova_tree_find(as->iova_tree, &target);

if (entry->perm == IOMMU_NONE && !info->notify_unmap) {
if (event->type == IOMMU_NOTIFIER_UNMAP && !info->notify_unmap) {
trace_vtd_page_walk_one_skip_unmap(entry->iova, entry->addr_mask);
return 0;
}

assert(hook_fn);

/* Update local IOVA mapped ranges */
if (entry->perm) {
if (event->type == IOMMU_NOTIFIER_MAP) {
if (mapped) {
/* If it's exactly the same translation, skip */
if (!memcmp(mapped, &target, sizeof(target))) {
Expand All @@ -1141,19 +1142,21 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info)
int ret;

/* Emulate an UNMAP */
event->type = IOMMU_NOTIFIER_UNMAP;
entry->perm = IOMMU_NONE;
trace_vtd_page_walk_one(info->domain_id,
entry->iova,
entry->translated_addr,
entry->addr_mask,
entry->perm);
ret = hook_fn(entry, private);
ret = hook_fn(event, private);
if (ret) {
return ret;
}
/* Drop any existing mapping */
iova_tree_remove(as->iova_tree, &target);
/* Recover the correct permission */
/* Recover the correct type */
event->type = IOMMU_NOTIFIER_MAP;
entry->perm = cache_perm;
}
}
Expand All @@ -1170,7 +1173,7 @@ static int vtd_page_walk_one(IOMMUTLBEntry *entry, vtd_page_walk_info *info)
trace_vtd_page_walk_one(info->domain_id, entry->iova,
entry->translated_addr, entry->addr_mask,
entry->perm);
return hook_fn(entry, private);
return hook_fn(event, private);
}

/**
Expand All @@ -1191,7 +1194,7 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
uint32_t offset;
uint64_t slpte;
uint64_t subpage_size, subpage_mask;
IOMMUTLBEntry entry;
IOMMUTLBEvent event;
uint64_t iova = start;
uint64_t iova_next;
int ret = 0;
Expand Down Expand Up @@ -1245,13 +1248,15 @@ static int vtd_page_walk_level(dma_addr_t addr, uint64_t start,
*
* In either case, we send an IOTLB notification down.
*/
entry.target_as = &address_space_memory;
entry.iova = iova & subpage_mask;
entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
entry.addr_mask = ~subpage_mask;
event.entry.target_as = &address_space_memory;
event.entry.iova = iova & subpage_mask;
event.entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur);
event.entry.addr_mask = ~subpage_mask;
/* NOTE: this is only meaningful if entry_valid == true */
entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw);
ret = vtd_page_walk_one(&entry, info);
event.entry.translated_addr = vtd_get_slpte_addr(slpte, info->aw);
event.type = event.entry.perm ? IOMMU_NOTIFIER_MAP :
IOMMU_NOTIFIER_UNMAP;
ret = vtd_page_walk_one(&event, info);
}

if (ret < 0) {
Expand Down Expand Up @@ -1430,10 +1435,10 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
return 0;
}

static int vtd_sync_shadow_page_hook(IOMMUTLBEntry *entry,
static int vtd_sync_shadow_page_hook(IOMMUTLBEvent *event,
void *private)
{
memory_region_notify_iommu((IOMMUMemoryRegion *)private, 0, *entry);
memory_region_notify_iommu(private, 0, *event);
return 0;
}

Expand Down Expand Up @@ -1993,14 +1998,17 @@ static void vtd_iotlb_page_invalidate_notify(IntelIOMMUState *s,
* page tables. We just deliver the PSI down to
* invalidate caches.
*/
IOMMUTLBEntry entry = {
.target_as = &address_space_memory,
.iova = addr,
.translated_addr = 0,
.addr_mask = size - 1,
.perm = IOMMU_NONE,
IOMMUTLBEvent event = {
.type = IOMMU_NOTIFIER_UNMAP,
.entry = {
.target_as = &address_space_memory,
.iova = addr,
.translated_addr = 0,
.addr_mask = size - 1,
.perm = IOMMU_NONE,
},
};
memory_region_notify_iommu(&vtd_as->iommu, 0, entry);
memory_region_notify_iommu(&vtd_as->iommu, 0, event);
}
}
}
Expand Down Expand Up @@ -2412,7 +2420,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
VTDAddressSpace *vtd_dev_as;
IOMMUTLBEntry entry;
IOMMUTLBEvent event;
struct VTDBus *vtd_bus;
hwaddr addr;
uint64_t sz;
Expand Down Expand Up @@ -2460,12 +2468,13 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
sz = VTD_PAGE_SIZE;
}

entry.target_as = &vtd_dev_as->as;
entry.addr_mask = sz - 1;
entry.iova = addr;
entry.perm = IOMMU_NONE;
entry.translated_addr = 0;
memory_region_notify_iommu(&vtd_dev_as->iommu, 0, entry);
event.type = IOMMU_NOTIFIER_UNMAP;
event.entry.target_as = &vtd_dev_as->as;
event.entry.addr_mask = sz - 1;
event.entry.iova = addr;
event.entry.perm = IOMMU_NONE;
event.entry.translated_addr = 0;
memory_region_notify_iommu(&vtd_dev_as->iommu, 0, event);

done:
return true;
Expand Down Expand Up @@ -3485,19 +3494,20 @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
size = remain = end - start + 1;

while (remain >= VTD_PAGE_SIZE) {
IOMMUTLBEntry entry;
IOMMUTLBEvent event;
uint64_t mask = get_naturally_aligned_size(start, remain, s->aw_bits);

assert(mask);

entry.iova = start;
entry.addr_mask = mask - 1;
entry.target_as = &address_space_memory;
entry.perm = IOMMU_NONE;
event.type = IOMMU_NOTIFIER_UNMAP;
event.entry.iova = start;
event.entry.addr_mask = mask - 1;
event.entry.target_as = &address_space_memory;
event.entry.perm = IOMMU_NONE;
/* This field is meaningless for unmap */
entry.translated_addr = 0;
event.entry.translated_addr = 0;

memory_region_notify_iommu_one(n, &entry);
memory_region_notify_iommu_one(n, &event);

start += mask;
remain -= mask;
Expand Down Expand Up @@ -3533,9 +3543,9 @@ static void vtd_address_space_refresh_all(IntelIOMMUState *s)
vtd_switch_address_space_all(s);
}

static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private)
static int vtd_replay_hook(IOMMUTLBEvent *event, void *private)
{
memory_region_notify_iommu_one((IOMMUNotifier *)private, entry);
memory_region_notify_iommu_one(private, event);
return 0;
}

Expand Down
32 changes: 18 additions & 14 deletions hw/misc/tz-mpc.c
Expand Up @@ -82,8 +82,10 @@ static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx,
/* Called when the LUT word at lutidx has changed from oldlut to newlut;
* must call the IOMMU notifiers for the changed blocks.
*/
IOMMUTLBEntry entry = {
.addr_mask = s->blocksize - 1,
IOMMUTLBEvent event = {
.entry = {
.addr_mask = s->blocksize - 1,
}
};
hwaddr addr = lutidx * s->blocksize * 32;
int i;
Expand All @@ -100,26 +102,28 @@ static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx,
block_is_ns = newlut & (1 << i);

trace_tz_mpc_iommu_notify(addr);
entry.iova = addr;
entry.translated_addr = addr;
event.entry.iova = addr;
event.entry.translated_addr = addr;

entry.perm = IOMMU_NONE;
memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry);
memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry);
event.type = IOMMU_NOTIFIER_UNMAP;
event.entry.perm = IOMMU_NONE;
memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, event);
memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, event);

entry.perm = IOMMU_RW;
event.type = IOMMU_NOTIFIER_MAP;
event.entry.perm = IOMMU_RW;
if (block_is_ns) {
entry.target_as = &s->blocked_io_as;
event.entry.target_as = &s->blocked_io_as;
} else {
entry.target_as = &s->downstream_as;
event.entry.target_as = &s->downstream_as;
}
memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry);
memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, event);
if (block_is_ns) {
entry.target_as = &s->downstream_as;
event.entry.target_as = &s->downstream_as;
} else {
entry.target_as = &s->blocked_io_as;
event.entry.target_as = &s->blocked_io_as;
}
memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry);
memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, event);
}
}

Expand Down
15 changes: 8 additions & 7 deletions hw/ppc/spapr_iommu.c
Expand Up @@ -445,7 +445,7 @@ static void spapr_tce_reset(DeviceState *dev)
static target_ulong put_tce_emu(SpaprTceTable *tcet, target_ulong ioba,
target_ulong tce)
{
IOMMUTLBEntry entry;
IOMMUTLBEvent event;
hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift;

Expand All @@ -457,12 +457,13 @@ static target_ulong put_tce_emu(SpaprTceTable *tcet, target_ulong ioba,

tcet->table[index] = tce;

entry.target_as = &address_space_memory,
entry.iova = (ioba - tcet->bus_offset) & page_mask;
entry.translated_addr = tce & page_mask;
entry.addr_mask = ~page_mask;
entry.perm = spapr_tce_iommu_access_flags(tce);
memory_region_notify_iommu(&tcet->iommu, 0, entry);
event.entry.target_as = &address_space_memory,
event.entry.iova = (ioba - tcet->bus_offset) & page_mask;
event.entry.translated_addr = tce & page_mask;
event.entry.addr_mask = ~page_mask;
event.entry.perm = spapr_tce_iommu_access_flags(tce);
event.type = event.entry.perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP;
memory_region_notify_iommu(&tcet->iommu, 0, event);

return H_SUCCESS;
}
Expand Down
27 changes: 16 additions & 11 deletions hw/s390x/s390-pci-inst.c
Expand Up @@ -602,15 +602,18 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
S390IOTLBEntry *entry)
{
S390IOTLBEntry *cache = g_hash_table_lookup(iommu->iotlb, &entry->iova);
IOMMUTLBEntry notify = {
.target_as = &address_space_memory,
.iova = entry->iova,
.translated_addr = entry->translated_addr,
.perm = entry->perm,
.addr_mask = ~PAGE_MASK,
IOMMUTLBEvent event = {
.type = entry->perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP,
.entry = {
.target_as = &address_space_memory,
.iova = entry->iova,
.translated_addr = entry->translated_addr,
.perm = entry->perm,
.addr_mask = ~PAGE_MASK,
},
};

if (entry->perm == IOMMU_NONE) {
if (event.type == IOMMU_NOTIFIER_UNMAP) {
if (!cache) {
goto out;
}
Expand All @@ -623,9 +626,11 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
goto out;
}

notify.perm = IOMMU_NONE;
memory_region_notify_iommu(&iommu->iommu_mr, 0, notify);
notify.perm = entry->perm;
event.type = IOMMU_NOTIFIER_UNMAP;
event.entry.perm = IOMMU_NONE;
memory_region_notify_iommu(&iommu->iommu_mr, 0, event);
event.type = IOMMU_NOTIFIER_MAP;
event.entry.perm = entry->perm;
}

cache = g_new(S390IOTLBEntry, 1);
Expand All @@ -637,7 +642,7 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
dec_dma_avail(iommu);
}

memory_region_notify_iommu(&iommu->iommu_mr, 0, notify);
memory_region_notify_iommu(&iommu->iommu_mr, 0, event);

out:
return iommu->dma_limit ? iommu->dma_limit->avail : 1;
Expand Down

0 comments on commit 5039caf

Please sign in to comment.