aboutsummaryrefslogtreecommitdiff
path: root/system/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'system/memory.c')
-rw-r--r--system/memory.c191
1 files changed, 127 insertions, 64 deletions
diff --git a/system/memory.c b/system/memory.c
index 5e6eb45..76b44b8 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -16,7 +16,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qapi/error.h"
-#include "exec/memory.h"
+#include "system/memory.h"
#include "qapi/visitor.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
@@ -24,16 +24,16 @@
#include "qemu/qemu-print.h"
#include "qom/object.h"
#include "trace.h"
-
-#include "exec/memory-internal.h"
-#include "exec/ram_addr.h"
-#include "sysemu/kvm.h"
-#include "sysemu/runstate.h"
-#include "sysemu/tcg.h"
+#include "system/ram_addr.h"
+#include "system/kvm.h"
+#include "system/runstate.h"
+#include "system/tcg.h"
#include "qemu/accel.h"
#include "hw/boards.h"
#include "migration/vmstate.h"
-#include "exec/address-spaces.h"
+#include "system/address-spaces.h"
+
+#include "memory-internal.h"
//#define DEBUG_UNASSIGNED
@@ -353,15 +353,6 @@ static void flatview_simplify(FlatView *view)
}
}
-static bool memory_region_big_endian(MemoryRegion *mr)
-{
-#if TARGET_BIG_ENDIAN
- return mr->ops->endianness != DEVICE_LITTLE_ENDIAN;
-#else
- return mr->ops->endianness == DEVICE_BIG_ENDIAN;
-#endif
-}
-
static void adjust_endianness(MemoryRegion *mr, uint64_t *data, MemOp op)
{
if ((op & MO_BSWAP) != devend_memop(mr->ops->endianness)) {
@@ -563,7 +554,7 @@ static MemTxResult access_with_adjusted_size(hwaddr addr,
/* FIXME: support unaligned access? */
access_size = MAX(MIN(size, access_size_max), access_size_min);
access_mask = MAKE_64BIT_MASK(0, access_size * 8);
- if (memory_region_big_endian(mr)) {
+ if (devend_big_endian(mr->ops->endianness)) {
for (i = 0; i < size; i += access_size) {
r |= access_fn(mr, addr + i, value, access_size,
(size - access_size - i) * 8, access_mask, attrs);
@@ -941,6 +932,38 @@ static void flat_range_coalesced_io_add(FlatRange *fr, AddressSpace *as)
}
}
+static void
+flat_range_coalesced_io_notify_listener_add_del(FlatRange *fr,
+ MemoryRegionSection *mrs,
+ MemoryListener *listener,
+ AddressSpace *as, bool add)
+{
+ CoalescedMemoryRange *cmr;
+ MemoryRegion *mr = fr->mr;
+ AddrRange tmp;
+
+ QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
+ tmp = addrrange_shift(cmr->addr,
+ int128_sub(fr->addr.start,
+ int128_make64(fr->offset_in_region)));
+
+ if (!addrrange_intersects(tmp, fr->addr)) {
+ return;
+ }
+ tmp = addrrange_intersection(tmp, fr->addr);
+
+ if (add && listener->coalesced_io_add) {
+ listener->coalesced_io_add(listener, mrs,
+ int128_get64(tmp.start),
+ int128_get64(tmp.size));
+ } else if (!add && listener->coalesced_io_del) {
+ listener->coalesced_io_del(listener, mrs,
+ int128_get64(tmp.start),
+ int128_get64(tmp.size));
+ }
+ }
+}
+
static void address_space_update_topology_pass(AddressSpace *as,
const FlatView *old_view,
const FlatView *new_view,
@@ -1206,7 +1229,7 @@ static void memory_region_do_init(MemoryRegion *mr,
char *name_array = g_strdup_printf("%s[*]", escaped_name);
if (!owner) {
- owner = container_get(qdev_get_machine(), "/unattached");
+ owner = machine_get_container("unattached");
}
object_property_add_child(owner, name_array, OBJECT(mr));
@@ -1359,7 +1382,7 @@ static void memory_region_ram_device_write(void *opaque, hwaddr addr,
static const MemoryRegionOps ram_device_mem_ops = {
.read = memory_region_ram_device_read,
.write = memory_region_ram_device_write,
- .endianness = DEVICE_HOST_ENDIAN,
+ .endianness = HOST_BIG_ENDIAN ? DEVICE_BIG_ENDIAN : DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 8,
@@ -1380,7 +1403,7 @@ bool memory_region_access_valid(MemoryRegion *mr,
{
if (mr->ops->valid.accepts
&& !mr->ops->valid.accepts(mr->opaque, addr, size, is_write, attrs)) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid %s at addr 0x%" HWADDR_PRIX
+ qemu_log_mask(LOG_INVALID_MEM, "Invalid %s at addr 0x%" HWADDR_PRIX
", size %u, region '%s', reason: rejected\n",
is_write ? "write" : "read",
addr, size, memory_region_name(mr));
@@ -1388,7 +1411,7 @@ bool memory_region_access_valid(MemoryRegion *mr,
}
if (!mr->ops->valid.unaligned && (addr & (size - 1))) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid %s at addr 0x%" HWADDR_PRIX
+ qemu_log_mask(LOG_INVALID_MEM, "Invalid %s at addr 0x%" HWADDR_PRIX
", size %u, region '%s', reason: unaligned\n",
is_write ? "write" : "read",
addr, size, memory_region_name(mr));
@@ -1402,7 +1425,7 @@ bool memory_region_access_valid(MemoryRegion *mr,
if (size > mr->ops->valid.max_access_size
|| size < mr->ops->valid.min_access_size) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid %s at addr 0x%" HWADDR_PRIX
+ qemu_log_mask(LOG_INVALID_MEM, "Invalid %s at addr 0x%" HWADDR_PRIX
", size %u, region '%s', reason: invalid size "
"(min:%u max:%u)\n",
is_write ? "write" : "read",
@@ -1604,7 +1627,7 @@ bool memory_region_init_resizeable_ram(MemoryRegion *mr,
return true;
}
-#ifdef CONFIG_POSIX
+#if defined(CONFIG_POSIX) && !defined(EMSCRIPTEN)
bool memory_region_init_ram_from_file(MemoryRegion *mr,
Object *owner,
const char *name,
@@ -1648,8 +1671,8 @@ bool memory_region_init_ram_from_fd(MemoryRegion *mr,
mr->readonly = !!(ram_flags & RAM_READONLY);
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
- mr->ram_block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, offset,
- &err);
+ mr->ram_block = qemu_ram_alloc_from_fd(size, size, NULL, mr, ram_flags, fd,
+ offset, false, &err);
if (err) {
mr->size = int128_zero();
object_unparent(OBJECT(mr));
@@ -2083,12 +2106,16 @@ RamDiscardManager *memory_region_get_ram_discard_manager(MemoryRegion *mr)
return mr->rdm;
}
-void memory_region_set_ram_discard_manager(MemoryRegion *mr,
- RamDiscardManager *rdm)
+int memory_region_set_ram_discard_manager(MemoryRegion *mr,
+ RamDiscardManager *rdm)
{
g_assert(memory_region_is_ram(mr));
- g_assert(!rdm || !mr->rdm);
+ if (mr->rdm && rdm) {
+ return -EBUSY;
+ }
+
mr->rdm = rdm;
+ return 0;
}
uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *rdm,
@@ -2111,7 +2138,7 @@ bool ram_discard_manager_is_populated(const RamDiscardManager *rdm,
int ram_discard_manager_replay_populated(const RamDiscardManager *rdm,
MemoryRegionSection *section,
- ReplayRamPopulate replay_fn,
+ ReplayRamDiscardState replay_fn,
void *opaque)
{
RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
@@ -2120,15 +2147,15 @@ int ram_discard_manager_replay_populated(const RamDiscardManager *rdm,
return rdmc->replay_populated(rdm, section, replay_fn, opaque);
}
-void ram_discard_manager_replay_discarded(const RamDiscardManager *rdm,
- MemoryRegionSection *section,
- ReplayRamDiscard replay_fn,
- void *opaque)
+int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm,
+ MemoryRegionSection *section,
+ ReplayRamDiscardState replay_fn,
+ void *opaque)
{
RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
g_assert(rdmc->replay_discarded);
- rdmc->replay_discarded(rdm, section, replay_fn, opaque);
+ return rdmc->replay_discarded(rdm, section, replay_fn, opaque);
}
void ram_discard_manager_register_listener(RamDiscardManager *rdm,
@@ -2151,18 +2178,14 @@ void ram_discard_manager_unregister_listener(RamDiscardManager *rdm,
}
/* Called with rcu_read_lock held. */
-bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr,
- ram_addr_t *ram_addr, bool *read_only,
- bool *mr_has_discard_manager, Error **errp)
+MemoryRegion *memory_translate_iotlb(IOMMUTLBEntry *iotlb, hwaddr *xlat_p,
+ Error **errp)
{
MemoryRegion *mr;
hwaddr xlat;
hwaddr len = iotlb->addr_mask + 1;
bool writable = iotlb->perm & IOMMU_WO;
- if (mr_has_discard_manager) {
- *mr_has_discard_manager = false;
- }
/*
* The IOMMU TLB entry we have just covers translation through
* this IOMMU to its immediate target. We need to translate
@@ -2172,7 +2195,7 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr,
&xlat, &len, writable, MEMTXATTRS_UNSPECIFIED);
if (!memory_region_is_ram(mr)) {
error_setg(errp, "iommu map to non memory area %" HWADDR_PRIx "", xlat);
- return false;
+ return NULL;
} else if (memory_region_has_ram_discard_manager(mr)) {
RamDiscardManager *rdm = memory_region_get_ram_discard_manager(mr);
MemoryRegionSection tmp = {
@@ -2180,9 +2203,6 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr,
.offset_within_region = xlat,
.size = int128_make64(len),
};
- if (mr_has_discard_manager) {
- *mr_has_discard_manager = true;
- }
/*
* Malicious VMs can map memory into the IOMMU, which is expected
* to remain discarded. vfio will pin all pages, populating memory.
@@ -2193,7 +2213,7 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr,
error_setg(errp, "iommu map to discarded memory (e.g., unplugged"
" via virtio-mem): %" HWADDR_PRIx "",
iotlb->translated_addr);
- return false;
+ return NULL;
}
}
@@ -2203,22 +2223,11 @@ bool memory_get_xlat_addr(IOMMUTLBEntry *iotlb, void **vaddr,
*/
if (len & iotlb->addr_mask) {
error_setg(errp, "iommu has granularity incompatible with target AS");
- return false;
- }
-
- if (vaddr) {
- *vaddr = memory_region_get_ram_ptr(mr) + xlat;
- }
-
- if (ram_addr) {
- *ram_addr = memory_region_get_ram_addr(mr) + xlat;
- }
-
- if (read_only) {
- *read_only = !writable || mr->readonly;
+ return NULL;
}
- return true;
+ *xlat_p = xlat;
+ return mr;
}
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
@@ -2552,7 +2561,8 @@ void memory_region_add_eventfd(MemoryRegion *mr,
unsigned i;
if (size) {
- adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE);
+ MemOp mop = (target_big_endian() ? MO_BE : MO_LE) | size_memop(size);
+ adjust_endianness(mr, &mrfd.data, mop);
}
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
@@ -2587,7 +2597,8 @@ void memory_region_del_eventfd(MemoryRegion *mr,
unsigned i;
if (size) {
- adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE);
+ MemOp mop = (target_big_endian() ? MO_BE : MO_LE) | size_memop(size);
+ adjust_endianness(mr, &mrfd.data, mop);
}
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
@@ -3015,8 +3026,10 @@ void memory_global_dirty_log_stop(unsigned int flags)
static void listener_add_address_space(MemoryListener *listener,
AddressSpace *as)
{
+ unsigned i;
FlatView *view;
FlatRange *fr;
+ MemoryRegionIoeventfd *fd;
if (listener->begin) {
listener->begin(listener);
@@ -3041,10 +3054,34 @@ static void listener_add_address_space(MemoryListener *listener,
if (listener->region_add) {
listener->region_add(listener, &section);
}
+
+ /* send coalesced io add notifications */
+ flat_range_coalesced_io_notify_listener_add_del(fr, &section,
+ listener, as, true);
+
if (fr->dirty_log_mask && listener->log_start) {
listener->log_start(listener, &section, 0, fr->dirty_log_mask);
}
}
+
+ /*
+ * register all eventfds for this address space for the newly registered
+ * listener.
+ */
+ for (i = 0; i < as->ioeventfd_nb; i++) {
+ fd = &as->ioeventfds[i];
+ MemoryRegionSection section = (MemoryRegionSection) {
+ .fv = view,
+ .offset_within_address_space = int128_get64(fd->addr.start),
+ .size = fd->addr.size,
+ };
+
+ if (listener->eventfd_add) {
+ listener->eventfd_add(listener, &section,
+ fd->match_data, fd->data, fd->e);
+ }
+ }
+
if (listener->commit) {
listener->commit(listener);
}
@@ -3054,8 +3091,10 @@ static void listener_add_address_space(MemoryListener *listener,
static void listener_del_address_space(MemoryListener *listener,
AddressSpace *as)
{
+ unsigned i;
FlatView *view;
FlatRange *fr;
+ MemoryRegionIoeventfd *fd;
if (listener->begin) {
listener->begin(listener);
@@ -3067,10 +3106,33 @@ static void listener_del_address_space(MemoryListener *listener,
if (fr->dirty_log_mask && listener->log_stop) {
listener->log_stop(listener, &section, fr->dirty_log_mask, 0);
}
+
+ /* send coalesced io del notifications */
+ flat_range_coalesced_io_notify_listener_add_del(fr, &section,
+ listener, as, false);
if (listener->region_del) {
listener->region_del(listener, &section);
}
}
+
+ /*
+ * de-register all eventfds for this address space for the current
+ * listener.
+ */
+ for (i = 0; i < as->ioeventfd_nb; i++) {
+ fd = &as->ioeventfds[i];
+ MemoryRegionSection section = (MemoryRegionSection) {
+ .fv = view,
+ .offset_within_address_space = int128_get64(fd->addr.start),
+ .size = fd->addr.size,
+ };
+
+ if (listener->eventfd_del) {
+ listener->eventfd_del(listener, &section,
+ fd->match_data, fd->data, fd->e);
+ }
+ }
+
if (listener->commit) {
listener->commit(listener);
}
@@ -3148,7 +3210,8 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
as->ioeventfds = NULL;
QTAILQ_INIT(&as->listeners);
QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
- as->bounce.in_use = false;
+ as->max_bounce_buffer_size = DEFAULT_MAX_BOUNCE_BUFFER_SIZE;
+ as->bounce_buffer_size = 0;
qemu_mutex_init(&as->map_client_list_lock);
QLIST_INIT(&as->map_client_list);
as->name = g_strdup(name ? name : "anonymous");
@@ -3158,7 +3221,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
static void do_address_space_destroy(AddressSpace *as)
{
- assert(!qatomic_read(&as->bounce.in_use));
+ assert(qatomic_read(&as->bounce_buffer_size) == 0);
assert(QLIST_EMPTY(&as->map_client_list));
qemu_mutex_destroy(&as->map_client_list_lock);