From 698feb5e13a2d763369909ce33f2bd7a7c1c11c0 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 7 Apr 2017 18:59:07 +0800 Subject: memory: add section range info for IOMMU notifier In this patch, IOMMUNotifier.{start|end} are introduced to store section information for a specific notifier. When notification occurs, we not only check the notification type (MAP|UNMAP), but also check whether the notified iova range overlaps with the range of specific IOMMU notifier, and skip those notifiers if not in the listened range. When removing an region, we need to make sure we removed the correct VFIOGuestIOMMU by checking the IOMMUNotifier.start address as well. This patch is solving the problem that vfio-pci devices receive duplicated UNMAP notification on x86 platform when vIOMMU is there. The issue is that x86 IOMMU has a (0, 2^64-1) IOMMU region, which is splitted by the (0xfee00000, 0xfeefffff) IRQ region. AFAIK this (splitted IOMMU region) is only happening on x86. This patch also helps vhost to leverage the new interface as well, so that vhost won't get duplicated cache flushes. In that sense, it's an slight performance improvement. Suggested-by: David Gibson Reviewed-by: Eric Auger Reviewed-by: Michael S. Tsirkin Acked-by: Alex Williamson Signed-off-by: Peter Xu Message-Id: <1491562755-23867-2-git-send-email-peterx@redhat.com> [ehabkost: included extra vhost_iommu_region_del() change from Peter Xu] Signed-off-by: Eduardo Habkost --- include/exec/memory.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'include/exec') diff --git a/include/exec/memory.h b/include/exec/memory.h index f20b191793..0840c89489 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -77,13 +77,30 @@ typedef enum { #define IOMMU_NOTIFIER_ALL (IOMMU_NOTIFIER_MAP | IOMMU_NOTIFIER_UNMAP) +struct IOMMUNotifier; +typedef void (*IOMMUNotify)(struct IOMMUNotifier *notifier, + IOMMUTLBEntry *data); + struct IOMMUNotifier { - void (*notify)(struct IOMMUNotifier *notifier, IOMMUTLBEntry *data); + IOMMUNotify notify; IOMMUNotifierFlag notifier_flags; + /* Notify for address space range start <= addr <= end */ + hwaddr start; + hwaddr end; QLIST_ENTRY(IOMMUNotifier) node; }; typedef struct IOMMUNotifier IOMMUNotifier; +static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn, + IOMMUNotifierFlag flags, + hwaddr start, hwaddr end) +{ + n->notify = fn; + n->notifier_flags = flags; + n->start = start; + n->end = end; +} + /* New-style MMIO accessors can indicate that the transaction failed. * A zero (MEMTX_OK) response means success; anything else is a failure * of some kind. The memory subsystem will bitwise-OR together results -- cgit v1.2.3-55-g7522 From 512fa40867e6118568756a81ddaf476a0fef0f32 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 7 Apr 2017 18:59:08 +0800 Subject: memory: provide IOMMU_NOTIFIER_FOREACH macro A new macro is provided to iterate all the IOMMU notifiers hooked under specific IOMMU memory region. Reviewed-by: David Gibson Reviewed-by: Eric Auger Reviewed-by: \"Michael S. Tsirkin\" Signed-off-by: Peter Xu Message-Id: <1491562755-23867-3-git-send-email-peterx@redhat.com> Signed-off-by: Eduardo Habkost --- include/exec/memory.h | 3 +++ memory.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include/exec') diff --git a/include/exec/memory.h b/include/exec/memory.h index 0840c89489..07e43daf20 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -239,6 +239,9 @@ struct MemoryRegion { IOMMUNotifierFlag iommu_notify_flags; }; +#define IOMMU_NOTIFIER_FOREACH(n, mr) \ + QLIST_FOREACH((n), &(mr)->iommu_notify, node) + /** * MemoryListener: callbacks structure for updates to the physical memory map * diff --git a/memory.c b/memory.c index 75ac595073..7496b3d3d5 100644 --- a/memory.c +++ b/memory.c @@ -1583,7 +1583,7 @@ static void memory_region_update_iommu_notify_flags(MemoryRegion *mr) IOMMUNotifierFlag flags = IOMMU_NOTIFIER_NONE; IOMMUNotifier *iommu_notifier; - QLIST_FOREACH(iommu_notifier, &mr->iommu_notify, node) { + IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) { flags |= iommu_notifier->notifier_flags; } @@ -1667,7 +1667,7 @@ void memory_region_notify_iommu(MemoryRegion *mr, request_flags = IOMMU_NOTIFIER_UNMAP; } - QLIST_FOREACH(iommu_notifier, &mr->iommu_notify, node) { + IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) { /* * Skip the notification if the notification does not overlap * with registered range. -- cgit v1.2.3-55-g7522 From de472e4a92f780d02b894001e004f4b4a350ec38 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 7 Apr 2017 18:59:09 +0800 Subject: memory: provide iommu_replay_all() This is an "global" version of existing memory_region_iommu_replay() - we announce the translations to all the registered notifiers, instead of a specific one. Reviewed-by: David Gibson Reviewed-by: \"Michael S. Tsirkin\" Signed-off-by: Peter Xu Message-Id: <1491562755-23867-4-git-send-email-peterx@redhat.com> Signed-off-by: Eduardo Habkost --- include/exec/memory.h | 8 ++++++++ memory.c | 9 +++++++++ 2 files changed, 17 insertions(+) (limited to 'include/exec') diff --git a/include/exec/memory.h b/include/exec/memory.h index 07e43daf20..fb7dff3405 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -712,6 +712,14 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr, void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n, bool is_write); +/** + * memory_region_iommu_replay_all: replay existing IOMMU translations + * to all the notifiers registered. + * + * @mr: the memory region to observe + */ +void memory_region_iommu_replay_all(MemoryRegion *mr); + /** * memory_region_unregister_iommu_notifier: unregister a notifier for * changes to IOMMU translation entries. diff --git a/memory.c b/memory.c index 7496b3d3d5..b4ed67b27a 100644 --- a/memory.c +++ b/memory.c @@ -1642,6 +1642,15 @@ void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n, } } +void memory_region_iommu_replay_all(MemoryRegion *mr) +{ + IOMMUNotifier *notifier; + + IOMMU_NOTIFIER_FOREACH(notifier, mr) { + memory_region_iommu_replay(mr, notifier, false); + } +} + void memory_region_unregister_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n) { -- cgit v1.2.3-55-g7522 From bd2bfa4c52e5f4dc6dbaa5be0521aedc31cb53d9 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 7 Apr 2017 18:59:10 +0800 Subject: memory: introduce memory_region_notify_one() Generalizing the notify logic in memory_region_notify_iommu() into a single function. This can be further used in customized replay() functions for IOMMUs. Reviewed-by: David Gibson Reviewed-by: Eric Auger Reviewed-by: \"Michael S. Tsirkin\" Signed-off-by: Peter Xu Message-Id: <1491562755-23867-5-git-send-email-peterx@redhat.com> Signed-off-by: Eduardo Habkost --- include/exec/memory.h | 15 +++++++++++++++ memory.c | 40 ++++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 16 deletions(-) (limited to 'include/exec') diff --git a/include/exec/memory.h b/include/exec/memory.h index fb7dff3405..055b3a8b23 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -687,6 +687,21 @@ uint64_t memory_region_iommu_get_min_page_size(MemoryRegion *mr); void memory_region_notify_iommu(MemoryRegion *mr, IOMMUTLBEntry entry); +/** + * memory_region_notify_one: notify a change in an IOMMU translation + * entry to a single notifier + * + * This works just like memory_region_notify_iommu(), but it only + * notifies a specific notifier, not all of them. + * + * @notifier: the notifier to be notified + * @entry: the new entry in the IOMMU translation table. The entry + * replaces all old entries for the same virtual I/O address range. + * Deleted entries have .@perm == 0. + */ +void memory_region_notify_one(IOMMUNotifier *notifier, + IOMMUTLBEntry *entry); + /** * memory_region_register_iommu_notifier: register a notifier for changes to * IOMMU translation entries. diff --git a/memory.c b/memory.c index b4ed67b27a..ded4bf13d6 100644 --- a/memory.c +++ b/memory.c @@ -1662,32 +1662,40 @@ void memory_region_unregister_iommu_notifier(MemoryRegion *mr, memory_region_update_iommu_notify_flags(mr); } -void memory_region_notify_iommu(MemoryRegion *mr, - IOMMUTLBEntry entry) +void memory_region_notify_one(IOMMUNotifier *notifier, + IOMMUTLBEntry *entry) { - IOMMUNotifier *iommu_notifier; IOMMUNotifierFlag request_flags; - assert(memory_region_is_iommu(mr)); + /* + * Skip the notification if the notification does not overlap + * with registered range. + */ + if (notifier->start > entry->iova + entry->addr_mask + 1 || + notifier->end < entry->iova) { + return; + } - if (entry.perm & IOMMU_RW) { + if (entry->perm & IOMMU_RW) { request_flags = IOMMU_NOTIFIER_MAP; } else { request_flags = IOMMU_NOTIFIER_UNMAP; } + if (notifier->notifier_flags & request_flags) { + notifier->notify(notifier, entry); + } +} + +void memory_region_notify_iommu(MemoryRegion *mr, + IOMMUTLBEntry entry) +{ + IOMMUNotifier *iommu_notifier; + + assert(memory_region_is_iommu(mr)); + IOMMU_NOTIFIER_FOREACH(iommu_notifier, mr) { - /* - * Skip the notification if the notification does not overlap - * with registered range. - */ - if (iommu_notifier->start > entry.iova + entry.addr_mask + 1 || - iommu_notifier->end < entry.iova) { - continue; - } - if (iommu_notifier->notifier_flags & request_flags) { - iommu_notifier->notify(iommu_notifier, &entry); - } + memory_region_notify_one(iommu_notifier, &entry); } } -- cgit v1.2.3-55-g7522 From faa362e3cc94bf739a89b457693e3fbd7a4b95c4 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 7 Apr 2017 18:59:11 +0800 Subject: memory: add MemoryRegionIOMMUOps.replay() callback Originally we have one memory_region_iommu_replay() function, which is the default behavior to replay the translations of the whole IOMMU region. However, on some platform like x86, we may want our own replay logic for IOMMU regions. This patch adds one more hook for IOMMUOps for the callback, and it'll override the default if set. Reviewed-by: David Gibson Reviewed-by: Eric Auger Reviewed-by: \"Michael S. Tsirkin\" Signed-off-by: Peter Xu Message-Id: <1491562755-23867-6-git-send-email-peterx@redhat.com> Signed-off-by: Eduardo Habkost --- include/exec/memory.h | 2 ++ memory.c | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'include/exec') diff --git a/include/exec/memory.h b/include/exec/memory.h index 055b3a8b23..c0280b7064 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -191,6 +191,8 @@ struct MemoryRegionIOMMUOps { void (*notify_flag_changed)(MemoryRegion *iommu, IOMMUNotifierFlag old_flags, IOMMUNotifierFlag new_flags); + /* Set this up to provide customized IOMMU replay function */ + void (*replay)(MemoryRegion *iommu, IOMMUNotifier *notifier); }; typedef struct CoalescedMemoryRange CoalescedMemoryRange; diff --git a/memory.c b/memory.c index ded4bf13d6..b782d5bc5a 100644 --- a/memory.c +++ b/memory.c @@ -1626,6 +1626,12 @@ void memory_region_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n, hwaddr addr, granularity; IOMMUTLBEntry iotlb; + /* If the IOMMU has its own replay callback, override */ + if (mr->iommu_ops->replay) { + mr->iommu_ops->replay(mr, n); + return; + } + granularity = memory_region_iommu_get_min_page_size(mr); for (addr = 0; addr < memory_region_size(mr); addr += granularity) { -- cgit v1.2.3-55-g7522 From f06a696dc958dd80f7eaf5be66fdefac77741ee0 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 7 Apr 2017 18:59:13 +0800 Subject: intel_iommu: provide its own replay() callback The default replay() don't work for VT-d since vt-d will have a huge default memory region which covers address range 0-(2^64-1). This will normally consumes a lot of time (which looks like a dead loop). The solution is simple - we don't walk over all the regions. Instead, we jump over the regions when we found that the page directories are empty. It'll greatly reduce the time to walk the whole region. To achieve this, we provided a page walk helper to do that, invoking corresponding hook function when we found an page we are interested in. vtd_page_walk_level() is the core logic for the page walking. It's interface is designed to suite further use case, e.g., to invalidate a range of addresses. Reviewed-by: Jason Wang Reviewed-by: David Gibson Reviewed-by: \"Michael S. Tsirkin\" Signed-off-by: Peter Xu Message-Id: <1491562755-23867-8-git-send-email-peterx@redhat.com> Signed-off-by: Eduardo Habkost --- hw/i386/intel_iommu.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++-- hw/i386/trace-events | 7 ++ include/exec/memory.h | 2 + 3 files changed, 186 insertions(+), 5 deletions(-) (limited to 'include/exec') diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 2412df4182..7af4e22958 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -595,6 +595,22 @@ static inline uint32_t vtd_get_agaw_from_context_entry(VTDContextEntry *ce) return 30 + (ce->hi & VTD_CONTEXT_ENTRY_AW) * 9; } +static inline uint64_t vtd_iova_limit(VTDContextEntry *ce) +{ + uint32_t ce_agaw = vtd_get_agaw_from_context_entry(ce); + return 1ULL << MIN(ce_agaw, VTD_MGAW); +} + +/* Return true if IOVA passes range check, otherwise false. */ +static inline bool vtd_iova_range_check(uint64_t iova, VTDContextEntry *ce) +{ + /* + * Check if @iova is above 2^X-1, where X is the minimum of MGAW + * in CAP_REG and AW in context-entry. + */ + return !(iova & ~(vtd_iova_limit(ce) - 1)); +} + static const uint64_t vtd_paging_entry_rsvd_field[] = { [0] = ~0ULL, /* For not large page */ @@ -630,13 +646,9 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write, uint32_t level = vtd_get_level_from_context_entry(ce); uint32_t offset; uint64_t slpte; - uint32_t ce_agaw = vtd_get_agaw_from_context_entry(ce); uint64_t access_right_check; - /* Check if @iova is above 2^X-1, where X is the minimum of MGAW - * in CAP_REG and AW in context-entry. - */ - if (iova & ~((1ULL << MIN(ce_agaw, VTD_MGAW)) - 1)) { + if (!vtd_iova_range_check(iova, ce)) { VTD_DPRINTF(GENERAL, "error: iova 0x%"PRIx64 " exceeds limits", iova); return -VTD_FR_ADDR_BEYOND_MGAW; } @@ -684,6 +696,134 @@ static int vtd_iova_to_slpte(VTDContextEntry *ce, uint64_t iova, bool is_write, } } +typedef int (*vtd_page_walk_hook)(IOMMUTLBEntry *entry, void *private); + +/** + * vtd_page_walk_level - walk over specific level for IOVA range + * + * @addr: base GPA addr to start the walk + * @start: IOVA range start address + * @end: IOVA range end address (start <= addr < end) + * @hook_fn: hook func to be called when detected page + * @private: private data to be passed into hook func + * @read: whether parent level has read permission + * @write: whether parent level has write permission + * @notify_unmap: whether we should notify invalid entries + */ +static int vtd_page_walk_level(dma_addr_t addr, uint64_t start, + uint64_t end, vtd_page_walk_hook hook_fn, + void *private, uint32_t level, + bool read, bool write, bool notify_unmap) +{ + bool read_cur, write_cur, entry_valid; + uint32_t offset; + uint64_t slpte; + uint64_t subpage_size, subpage_mask; + IOMMUTLBEntry entry; + uint64_t iova = start; + uint64_t iova_next; + int ret = 0; + + trace_vtd_page_walk_level(addr, level, start, end); + + subpage_size = 1ULL << vtd_slpt_level_shift(level); + subpage_mask = vtd_slpt_level_page_mask(level); + + while (iova < end) { + iova_next = (iova & subpage_mask) + subpage_size; + + offset = vtd_iova_level_offset(iova, level); + slpte = vtd_get_slpte(addr, offset); + + if (slpte == (uint64_t)-1) { + trace_vtd_page_walk_skip_read(iova, iova_next); + goto next; + } + + if (vtd_slpte_nonzero_rsvd(slpte, level)) { + trace_vtd_page_walk_skip_reserve(iova, iova_next); + goto next; + } + + /* Permissions are stacked with parents' */ + read_cur = read && (slpte & VTD_SL_R); + write_cur = write && (slpte & VTD_SL_W); + + /* + * As long as we have either read/write permission, this is a + * valid entry. The rule works for both page entries and page + * table entries. + */ + entry_valid = read_cur | write_cur; + + if (vtd_is_last_slpte(slpte, level)) { + entry.target_as = &address_space_memory; + entry.iova = iova & subpage_mask; + /* NOTE: this is only meaningful if entry_valid == true */ + entry.translated_addr = vtd_get_slpte_addr(slpte); + entry.addr_mask = ~subpage_mask; + entry.perm = IOMMU_ACCESS_FLAG(read_cur, write_cur); + if (!entry_valid && !notify_unmap) { + trace_vtd_page_walk_skip_perm(iova, iova_next); + goto next; + } + trace_vtd_page_walk_one(level, entry.iova, entry.translated_addr, + entry.addr_mask, entry.perm); + if (hook_fn) { + ret = hook_fn(&entry, private); + if (ret < 0) { + return ret; + } + } + } else { + if (!entry_valid) { + trace_vtd_page_walk_skip_perm(iova, iova_next); + goto next; + } + ret = vtd_page_walk_level(vtd_get_slpte_addr(slpte), iova, + MIN(iova_next, end), hook_fn, private, + level - 1, read_cur, write_cur, + notify_unmap); + if (ret < 0) { + return ret; + } + } + +next: + iova = iova_next; + } + + return 0; +} + +/** + * vtd_page_walk - walk specific IOVA range, and call the hook + * + * @ce: context entry to walk upon + * @start: IOVA address to start the walk + * @end: IOVA range end address (start <= addr < end) + * @hook_fn: the hook that to be called for each detected area + * @private: private data for the hook function + */ +static int vtd_page_walk(VTDContextEntry *ce, uint64_t start, uint64_t end, + vtd_page_walk_hook hook_fn, void *private) +{ + dma_addr_t addr = vtd_get_slpt_base_from_context(ce); + uint32_t level = vtd_get_level_from_context_entry(ce); + + if (!vtd_iova_range_check(start, ce)) { + return -VTD_FR_ADDR_BEYOND_MGAW; + } + + if (!vtd_iova_range_check(end, ce)) { + /* Fix end so that it reaches the maximum */ + end = vtd_iova_limit(ce); + } + + return vtd_page_walk_level(addr, start, end, hook_fn, private, + level, true, true, false); +} + /* Map a device to its corresponding domain (context-entry) */ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num, uint8_t devfn, VTDContextEntry *ce) @@ -2402,6 +2542,37 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) return vtd_dev_as; } +static int vtd_replay_hook(IOMMUTLBEntry *entry, void *private) +{ + memory_region_notify_one((IOMMUNotifier *)private, entry); + return 0; +} + +static void vtd_iommu_replay(MemoryRegion *mr, IOMMUNotifier *n) +{ + VTDAddressSpace *vtd_as = container_of(mr, VTDAddressSpace, iommu); + IntelIOMMUState *s = vtd_as->iommu_state; + uint8_t bus_n = pci_bus_num(vtd_as->bus); + VTDContextEntry ce; + + if (vtd_dev_to_context_entry(s, bus_n, vtd_as->devfn, &ce) == 0) { + /* + * Scanned a valid context entry, walk over the pages and + * notify when needed. + */ + trace_vtd_replay_ce_valid(bus_n, PCI_SLOT(vtd_as->devfn), + PCI_FUNC(vtd_as->devfn), + VTD_CONTEXT_ENTRY_DID(ce.hi), + ce.hi, ce.lo); + vtd_page_walk(&ce, 0, ~0ULL, vtd_replay_hook, (void *)n); + } else { + trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn), + PCI_FUNC(vtd_as->devfn)); + } + + return; +} + /* Do the initialization. It will also be called when reset, so pay * attention when adding new initialization stuff. */ @@ -2416,6 +2587,7 @@ static void vtd_init(IntelIOMMUState *s) s->iommu_ops.translate = vtd_iommu_translate; s->iommu_ops.notify_flag_changed = vtd_iommu_notify_flag_changed; + s->iommu_ops.replay = vtd_iommu_replay; s->root = 0; s->root_extended = false; s->dmar_enabled = false; diff --git a/hw/i386/trace-events b/hw/i386/trace-events index baed874a80..f725bca33e 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -30,6 +30,13 @@ vtd_iotlb_cc_hit(uint8_t bus, uint8_t devfn, uint64_t high, uint64_t low, uint32 vtd_iotlb_cc_update(uint8_t bus, uint8_t devfn, uint64_t high, uint64_t low, uint32_t gen1, uint32_t gen2) "IOTLB context update bus 0x%"PRIx8" devfn 0x%"PRIx8" high 0x%"PRIx64" low 0x%"PRIx64" gen %"PRIu32" -> gen %"PRIu32 vtd_iotlb_reset(const char *reason) "IOTLB reset (reason: %s)" vtd_fault_disabled(void) "Fault processing disabled for context entry" +vtd_replay_ce_valid(uint8_t bus, uint8_t dev, uint8_t fn, uint16_t domain, uint64_t hi, uint64_t lo) "replay valid context device %02"PRIx8":%02"PRIx8".%02"PRIx8" domain 0x%"PRIx16" hi 0x%"PRIx64" lo 0x%"PRIx64 +vtd_replay_ce_invalid(uint8_t bus, uint8_t dev, uint8_t fn) "replay invalid context device %02"PRIx8":%02"PRIx8".%02"PRIx8 +vtd_page_walk_level(uint64_t addr, uint32_t level, uint64_t start, uint64_t end) "walk (base=0x%"PRIx64", level=%"PRIu32") iova range 0x%"PRIx64" - 0x%"PRIx64 +vtd_page_walk_one(uint32_t level, uint64_t iova, uint64_t gpa, uint64_t mask, int perm) "detected page level 0x%"PRIx32" iova 0x%"PRIx64" -> gpa 0x%"PRIx64" mask 0x%"PRIx64" perm %d" +vtd_page_walk_skip_read(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to unable to read" +vtd_page_walk_skip_perm(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to perm empty" +vtd_page_walk_skip_reserve(uint64_t iova, uint64_t next) "Page walk skip iova 0x%"PRIx64" - 0x%"PRIx64" due to rsrv set" # hw/i386/amd_iommu.c amdvi_evntlog_fail(uint64_t addr, uint32_t head) "error: fail to write at addr 0x%"PRIx64" + offset 0x%"PRIx32 diff --git a/include/exec/memory.h b/include/exec/memory.h index c0280b7064..c4fc94d504 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -55,6 +55,8 @@ typedef enum { IOMMU_RW = 3, } IOMMUAccessFlags; +#define IOMMU_ACCESS_FLAG(r, w) (((r) ? IOMMU_RO : 0) | ((w) ? IOMMU_WO : 0)) + struct IOMMUTLBEntry { AddressSpace *target_as; hwaddr iova; -- cgit v1.2.3-55-g7522