#include "cpu.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"
-#include "exec/ioport.h"
#include "qapi/visitor.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
EventNotifier *e;
};
-static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd a,
- MemoryRegionIoeventfd b)
+static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd *a,
+ MemoryRegionIoeventfd *b)
{
- if (int128_lt(a.addr.start, b.addr.start)) {
+ if (int128_lt(a->addr.start, b->addr.start)) {
return true;
- } else if (int128_gt(a.addr.start, b.addr.start)) {
+ } else if (int128_gt(a->addr.start, b->addr.start)) {
return false;
- } else if (int128_lt(a.addr.size, b.addr.size)) {
+ } else if (int128_lt(a->addr.size, b->addr.size)) {
return true;
- } else if (int128_gt(a.addr.size, b.addr.size)) {
+ } else if (int128_gt(a->addr.size, b->addr.size)) {
return false;
- } else if (a.match_data < b.match_data) {
+ } else if (a->match_data < b->match_data) {
return true;
- } else if (a.match_data > b.match_data) {
+ } else if (a->match_data > b->match_data) {
return false;
- } else if (a.match_data) {
- if (a.data < b.data) {
+ } else if (a->match_data) {
+ if (a->data < b->data) {
return true;
- } else if (a.data > b.data) {
+ } else if (a->data > b->data) {
return false;
}
}
- if (a.e < b.e) {
+ if (a->e < b->e) {
return true;
- } else if (a.e > b.e) {
+ } else if (a->e > b->e) {
return false;
}
return false;
}
-static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a,
- MemoryRegionIoeventfd b)
+static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd *a,
+ MemoryRegionIoeventfd *b)
{
return !memory_region_ioeventfd_before(a, b)
&& !memory_region_ioeventfd_before(b, a);
bool readonly;
};
-typedef struct AddressSpaceOps AddressSpaceOps;
-
#define FOR_EACH_FLAT_RANGE(var, view) \
for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
while (iold < fds_old_nb || inew < fds_new_nb) {
if (iold < fds_old_nb
&& (inew == fds_new_nb
- || memory_region_ioeventfd_before(fds_old[iold],
- fds_new[inew]))) {
+ || memory_region_ioeventfd_before(&fds_old[iold],
+ &fds_new[inew]))) {
fd = &fds_old[iold];
section = (MemoryRegionSection) {
.fv = address_space_to_flatview(as),
++iold;
} else if (inew < fds_new_nb
&& (iold == fds_old_nb
- || memory_region_ioeventfd_before(fds_new[inew],
- fds_old[iold]))) {
+ || memory_region_ioeventfd_before(&fds_new[inew],
+ &fds_old[iold]))) {
fd = &fds_new[inew];
section = (MemoryRegionSection) {
.fv = address_space_to_flatview(as),
}
static bool unassigned_mem_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
+ unsigned size, bool is_write,
+ MemTxAttrs attrs)
{
return false;
}
bool memory_region_access_valid(MemoryRegion *mr,
hwaddr addr,
unsigned size,
- bool is_write)
+ bool is_write,
+ MemTxAttrs attrs)
{
int access_size_min, access_size_max;
int access_size, i;
access_size = MAX(MIN(size, access_size_max), access_size_min);
for (i = 0; i < size; i += access_size) {
if (!mr->ops->valid.accepts(mr->opaque, addr + i, access_size,
- is_write)) {
+ is_write, attrs)) {
return false;
}
}
{
MemTxResult r;
- if (!memory_region_access_valid(mr, addr, size, false)) {
+ if (!memory_region_access_valid(mr, addr, size, false, attrs)) {
*pval = unassigned_mem_read(mr, addr, size);
return MEMTX_DECODE_ERROR;
}
ioeventfd.match_data = mr->ioeventfds[i].match_data;
ioeventfd.e = mr->ioeventfds[i].e;
- if (memory_region_ioeventfd_equal(ioeventfd, mr->ioeventfds[i])) {
+ if (memory_region_ioeventfd_equal(&ioeventfd, &mr->ioeventfds[i])) {
event_notifier_set(ioeventfd.e);
return true;
}
unsigned size,
MemTxAttrs attrs)
{
- if (!memory_region_access_valid(mr, addr, size, true)) {
+ if (!memory_region_access_valid(mr, addr, size, true, attrs)) {
unassigned_mem_write(mr, addr, data, size);
return MEMTX_DECODE_ERROR;
}
iommu_mr = IOMMU_MEMORY_REGION(mr);
assert(n->notifier_flags != IOMMU_NOTIFIER_NONE);
assert(n->start <= n->end);
+ assert(n->iommu_idx >= 0 &&
+ n->iommu_idx < memory_region_iommu_num_indexes(iommu_mr));
+
QLIST_INSERT_HEAD(&iommu_mr->iommu_notify, n, node);
memory_region_update_iommu_notify_flags(iommu_mr);
}
granularity = memory_region_iommu_get_min_page_size(iommu_mr);
for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
- iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE);
+ iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, n->iommu_idx);
if (iotlb.perm != IOMMU_NONE) {
n->notify(n, &iotlb);
}
}
void memory_region_notify_iommu(IOMMUMemoryRegion *iommu_mr,
+ int iommu_idx,
IOMMUTLBEntry entry)
{
IOMMUNotifier *iommu_notifier;
assert(memory_region_is_iommu(MEMORY_REGION(iommu_mr)));
IOMMU_NOTIFIER_FOREACH(iommu_notifier, iommu_mr) {
- memory_region_notify_one(iommu_notifier, &entry);
+ if (iommu_notifier->iommu_idx == iommu_idx) {
+ memory_region_notify_one(iommu_notifier, &entry);
+ }
}
}
return imrc->get_attr(iommu_mr, attr, data);
}
+int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr,
+ MemTxAttrs attrs)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
+
+ if (!imrc->attrs_to_index) {
+ return 0;
+ }
+
+ return imrc->attrs_to_index(iommu_mr, attrs);
+}
+
+int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr)
+{
+ IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
+
+ if (!imrc->num_indexes) {
+ return 1;
+ }
+
+ return imrc->num_indexes(iommu_mr);
+}
+
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
{
uint8_t mask = 1 << client;
}
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
- if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) {
+ if (memory_region_ioeventfd_before(&mrfd, &mr->ioeventfds[i])) {
break;
}
}
}
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
- if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) {
+ if (memory_region_ioeventfd_equal(&mrfd, &mr->ioeventfds[i])) {
break;
}
}
int128_sub((size), int128_one())) : 0)
#define MTREE_INDENT " "
+static void mtree_expand_owner(fprintf_function mon_printf, void *f,
+ const char *label, Object *obj)
+{
+ DeviceState *dev = (DeviceState *) object_dynamic_cast(obj, TYPE_DEVICE);
+
+ mon_printf(f, " %s:{%s", label, dev ? "dev" : "obj");
+ if (dev && dev->id) {
+ mon_printf(f, " id=%s", dev->id);
+ } else {
+ gchar *canonical_path = object_get_canonical_path(obj);
+ if (canonical_path) {
+ mon_printf(f, " path=%s", canonical_path);
+ g_free(canonical_path);
+ } else {
+ mon_printf(f, " type=%s", object_get_typename(obj));
+ }
+ }
+ mon_printf(f, "}");
+}
+
+static void mtree_print_mr_owner(fprintf_function mon_printf, void *f,
+ const MemoryRegion *mr)
+{
+ Object *owner = mr->owner;
+ Object *parent = memory_region_owner((MemoryRegion *)mr);
+
+ if (!owner && !parent) {
+ mon_printf(f, " orphan");
+ return;
+ }
+ if (owner) {
+ mtree_expand_owner(mon_printf, f, "owner", owner);
+ }
+ if (parent && parent != owner) {
+ mtree_expand_owner(mon_printf, f, "parent", parent);
+ }
+}
+
static void mtree_print_mr(fprintf_function mon_printf, void *f,
const MemoryRegion *mr, unsigned int level,
hwaddr base,
- MemoryRegionListHead *alias_print_queue)
+ MemoryRegionListHead *alias_print_queue,
+ bool owner)
{
MemoryRegionList *new_ml, *ml, *next_ml;
MemoryRegionListHead submr_print_queue;
}
mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx
" (prio %d, %s): alias %s @%s " TARGET_FMT_plx
- "-" TARGET_FMT_plx "%s\n",
+ "-" TARGET_FMT_plx "%s",
cur_start, cur_end,
mr->priority,
memory_region_type((MemoryRegion *)mr),
mr->alias_offset,
mr->alias_offset + MR_SIZE(mr->size),
mr->enabled ? "" : " [disabled]");
+ if (owner) {
+ mtree_print_mr_owner(mon_printf, f, mr);
+ }
} else {
mon_printf(f,
- TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s): %s%s\n",
+ TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s): %s%s",
cur_start, cur_end,
mr->priority,
memory_region_type((MemoryRegion *)mr),
memory_region_name(mr),
mr->enabled ? "" : " [disabled]");
+ if (owner) {
+ mtree_print_mr_owner(mon_printf, f, mr);
+ }
}
+ mon_printf(f, "\n");
QTAILQ_INIT(&submr_print_queue);
QTAILQ_FOREACH(ml, &submr_print_queue, mrqueue) {
mtree_print_mr(mon_printf, f, ml->mr, level + 1, cur_start,
- alias_print_queue);
+ alias_print_queue, owner);
}
QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, mrqueue, next_ml) {
void *f;
int counter;
bool dispatch_tree;
+ bool owner;
};
static void mtree_print_flatview(gpointer key, gpointer value,
mr = range->mr;
if (range->offset_in_region) {
p(f, MTREE_INDENT TARGET_FMT_plx "-"
- TARGET_FMT_plx " (prio %d, %s): %s @" TARGET_FMT_plx "\n",
+ TARGET_FMT_plx " (prio %d, %s): %s @" TARGET_FMT_plx,
int128_get64(range->addr.start),
int128_get64(range->addr.start) + MR_SIZE(range->addr.size),
mr->priority,
range->offset_in_region);
} else {
p(f, MTREE_INDENT TARGET_FMT_plx "-"
- TARGET_FMT_plx " (prio %d, %s): %s\n",
+ TARGET_FMT_plx " (prio %d, %s): %s",
int128_get64(range->addr.start),
int128_get64(range->addr.start) + MR_SIZE(range->addr.size),
mr->priority,
range->readonly ? "rom" : memory_region_type(mr),
memory_region_name(mr));
}
+ if (fvi->owner) {
+ mtree_print_mr_owner(p, f, mr);
+ }
+ p(f, "\n");
range++;
}
}
void mtree_info(fprintf_function mon_printf, void *f, bool flatview,
- bool dispatch_tree)
+ bool dispatch_tree, bool owner)
{
MemoryRegionListHead ml_head;
MemoryRegionList *ml, *ml2;
.mon_printf = mon_printf,
.f = f,
.counter = 0,
- .dispatch_tree = dispatch_tree
+ .dispatch_tree = dispatch_tree,
+ .owner = owner,
};
GArray *fv_address_spaces;
GHashTable *views = g_hash_table_new(g_direct_hash, g_direct_equal);
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
mon_printf(f, "address-space: %s\n", as->name);
- mtree_print_mr(mon_printf, f, as->root, 1, 0, &ml_head);
+ mtree_print_mr(mon_printf, f, as->root, 1, 0, &ml_head, owner);
mon_printf(f, "\n");
}
/* print aliased regions */
QTAILQ_FOREACH(ml, &ml_head, mrqueue) {
mon_printf(f, "memory-region: %s\n", memory_region_name(ml->mr));
- mtree_print_mr(mon_printf, f, ml->mr, 1, 0, &ml_head);
+ mtree_print_mr(mon_printf, f, ml->mr, 1, 0, &ml_head, owner);
mon_printf(f, "\n");
}