* GNU GPL, version 2 or (at your option) any later version.
*/
+#include "qemu/osdep.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"
#include "qom/object.h"
#include "trace.h"
-#include <assert.h>
#include "exec/memory-internal.h"
#include "exec/ram_addr.h"
+#include "sysemu/kvm.h"
#include "sysemu/sysemu.h"
//#define DEBUG_UNASSIGNED
qemu_ram_free(mr->ram_addr);
}
-static void memory_region_destructor_ram_from_ptr(MemoryRegion *mr)
-{
- qemu_ram_free_from_ptr(mr->ram_addr);
-}
-
static void memory_region_destructor_rom_device(MemoryRegion *mr)
{
qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK);
const char *name,
uint64_t size)
{
- if (!owner) {
- owner = container_get(qdev_get_machine(), "/unattached");
- }
-
object_initialize(mr, sizeof(*mr), TYPE_MEMORY_REGION);
mr->size = int128_make64(size);
if (size == UINT64_MAX) {
mr->size = int128_2_64();
}
mr->name = g_strdup(name);
+ mr->owner = owner;
if (name) {
char *escaped_name = memory_region_escape_name(name);
char *name_array = g_strdup_printf("%s[*]", escaped_name);
+
+ if (!owner) {
+ owner = container_get(qdev_get_machine(), "/unattached");
+ }
+
object_property_add_child(owner, name_array, OBJECT(mr), &error_abort);
object_unref(OBJECT(mr));
g_free(name_array);
}
}
-static void memory_region_get_addr(Object *obj, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void memory_region_get_addr(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
MemoryRegion *mr = MEMORY_REGION(obj);
uint64_t value = mr->addr;
- visit_type_uint64(v, &value, name, errp);
+ visit_type_uint64(v, name, &value, errp);
}
-static void memory_region_get_container(Object *obj, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void memory_region_get_container(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
{
MemoryRegion *mr = MEMORY_REGION(obj);
gchar *path = (gchar *)"";
if (mr->container) {
path = object_get_canonical_path(OBJECT(mr->container));
}
- visit_type_str(v, &path, name, errp);
+ visit_type_str(v, name, &path, errp);
if (mr->container) {
g_free(path);
}
return OBJECT(mr->container);
}
-static void memory_region_get_priority(Object *obj, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void memory_region_get_priority(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
{
MemoryRegion *mr = MEMORY_REGION(obj);
int32_t value = mr->priority;
- visit_type_int32(v, &value, name, errp);
+ visit_type_int32(v, name, &value, errp);
}
static bool memory_region_get_may_overlap(Object *obj, Error **errp)
return mr->may_overlap;
}
-static void memory_region_get_size(Object *obj, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void memory_region_get_size(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
{
MemoryRegion *mr = MEMORY_REGION(obj);
uint64_t value = memory_region_size(mr);
- visit_type_uint64(v, &value, name, errp);
+ visit_type_uint64(v, name, &value, errp);
}
static void memory_region_initfn(Object *obj)
return r;
}
+/* Return true if an eventfd was signalled */
+static bool memory_region_dispatch_write_eventfds(MemoryRegion *mr,
+ hwaddr addr,
+ uint64_t data,
+ unsigned size,
+ MemTxAttrs attrs)
+{
+ MemoryRegionIoeventfd ioeventfd = {
+ .addr = addrrange_make(int128_make64(addr), int128_make64(size)),
+ .data = data,
+ };
+ unsigned i;
+
+ for (i = 0; i < mr->ioeventfd_nb; i++) {
+ ioeventfd.match_data = mr->ioeventfds[i].match_data;
+ ioeventfd.e = mr->ioeventfds[i].e;
+
+ if (memory_region_ioeventfd_equal(ioeventfd, mr->ioeventfds[i])) {
+ event_notifier_set(ioeventfd.e);
+ return true;
+ }
+ }
+
+ return false;
+}
+
MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
hwaddr addr,
uint64_t data,
adjust_endianness(mr, &data, size);
+ if ((!kvm_eventfds_enabled()) &&
+ memory_region_dispatch_write_eventfds(mr, addr, data, size, attrs)) {
+ return MEMTX_OK;
+ }
+
if (mr->ops->write) {
return access_with_adjusted_size(addr, &data, size,
mr->ops->impl.min_access_size,
memory_region_init(mr, owner, name, size);
mr->ram = true;
mr->terminates = true;
- mr->destructor = memory_region_destructor_ram_from_ptr;
+ mr->destructor = memory_region_destructor_ram;
mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
/* qemu_ram_alloc_from_ptr cannot fail with ptr != NULL. */
* The memory region is a child of its owner. As long as the
* owner doesn't call unparent itself on the memory region,
* ref-ing the owner will also keep the memory region alive.
- * Memory regions without an owner are supposed to never go away,
- * but we still ref/unref them for debugging purposes.
+ * Memory regions without an owner are supposed to never go away;
+ * we do not ref/unref them because it slows down DMA sensibly.
*/
- Object *obj = OBJECT(mr);
- if (obj && obj->parent) {
- object_ref(obj->parent);
- } else {
- object_ref(obj);
+ if (mr && mr->owner) {
+ object_ref(mr->owner);
}
}
void memory_region_unref(MemoryRegion *mr)
{
- Object *obj = OBJECT(mr);
- if (obj && obj->parent) {
- object_unref(obj->parent);
- } else {
- object_unref(obj);
+ if (mr && mr->owner) {
+ object_unref(mr->owner);
}
}
return mr->name;
}
-bool memory_region_is_ram(MemoryRegion *mr)
-{
- return mr->ram;
-}
-
bool memory_region_is_skip_dump(MemoryRegion *mr)
{
return mr->skip_dump;
return memory_region_get_dirty_log_mask(mr) & (1 << client);
}
-bool memory_region_is_rom(MemoryRegion *mr)
-{
- return mr->ram && mr->readonly;
-}
-
-bool memory_region_is_iommu(MemoryRegion *mr)
-{
- return mr->iommu_ops;
-}
-
void memory_region_register_iommu_notifier(MemoryRegion *mr, Notifier *n)
{
notifier_list_add(&mr->iommu_notify, n);
void *memory_region_get_ram_ptr(MemoryRegion *mr)
{
- if (mr->alias) {
- return memory_region_get_ram_ptr(mr->alias) + mr->alias_offset;
- }
+ void *ptr;
+ uint64_t offset = 0;
+ rcu_read_lock();
+ while (mr->alias) {
+ offset += mr->alias_offset;
+ mr = mr->alias;
+ }
assert(mr->ram_addr != RAM_ADDR_INVALID);
+ ptr = qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
+ rcu_read_unlock();
- return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK);
+ return ptr + offset;
}
void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp)
mr->global_locking = false;
}
+static bool userspace_eventfd_warning;
+
void memory_region_add_eventfd(MemoryRegion *mr,
hwaddr addr,
unsigned size,
};
unsigned i;
- adjust_endianness(mr, &mrfd.data, size);
+ if (kvm_enabled() && (!(kvm_eventfds_enabled() ||
+ userspace_eventfd_warning))) {
+ userspace_eventfd_warning = true;
+ error_report("Using eventfd without MMIO binding in KVM. "
+ "Suboptimal performance expected");
+ }
+
+ if (size) {
+ adjust_endianness(mr, &mrfd.data, size);
+ }
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) {
};
unsigned i;
- adjust_endianness(mr, &mrfd.data, size);
+ if (size) {
+ adjust_endianness(mr, &mrfd.data, size);
+ }
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) {
memory_region_transaction_commit();
}
-ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr)
-{
- return mr->ram_addr;
-}
-
uint64_t memory_region_get_alignment(const MemoryRegion *mr)
{
return mr->align;
{
memory_region_ref(root);
memory_region_transaction_begin();
+ as->ref_count = 1;
as->root = root;
+ as->malloced = false;
as->current_map = g_new(FlatView, 1);
flatview_init(as->current_map);
as->ioeventfd_nb = 0;
static void do_address_space_destroy(AddressSpace *as)
{
MemoryListener *listener;
+ bool do_free = as->malloced;
address_space_destroy_dispatch(as);
g_free(as->name);
g_free(as->ioeventfds);
memory_region_unref(as->root);
+ if (do_free) {
+ g_free(as);
+ }
+}
+
+AddressSpace *address_space_init_shareable(MemoryRegion *root, const char *name)
+{
+ AddressSpace *as;
+
+ QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
+ if (root == as->root && as->malloced) {
+ as->ref_count++;
+ return as;
+ }
+ }
+
+ as = g_malloc0(sizeof *as);
+ address_space_init(as, root, name);
+ as->malloced = true;
+ return as;
}
void address_space_destroy(AddressSpace *as)
{
MemoryRegion *root = as->root;
+ as->ref_count--;
+ if (as->ref_count) {
+ return;
+ }
/* Flush out anything from MemoryListeners listening in on this */
memory_region_transaction_begin();
as->root = NULL;