Merge remote-tracking branch 'qemu-kvm/memory/core' into staging

* qemu-kvm/memory/core: (30 commits)
  memory: allow phys_map tree paths to terminate early
  memory: unify PhysPageEntry::node and ::leaf
  memory: change phys_page_set() to set multiple pages
  memory: switch phys_page_set() to a recursive implementation
  memory: replace phys_page_find_alloc() with phys_page_set()
  memory: simplify multipage/subpage registration
  memory: give phys_page_find() its own tree search loop
  memory: make phys_page_find() return a MemoryRegionSection
  memory: move tlb flush to MemoryListener commit callback
  memory: unify the two branches of cpu_register_physical_memory_log()
  memory: fix RAM subpages in newly initialized pages
  memory: compress phys_map node pointers to 16 bits
  memory: store MemoryRegionSection pointers in phys_map
  memory: unify phys_map last level with intermediate levels
  memory: remove first level of l1_phys_map
  memory: change memory registration to rebuild the memory map on each change
  memory: support stateless memory listeners
  memory: split memory listener for the two address spaces
  xen: ignore I/O memory regions
  memory: allow MemoryListeners to observe a specific address space
  ...
This commit is contained in:
Anthony Liguori 2012-03-01 15:26:25 -06:00
commit 14655e482b
9 changed files with 921 additions and 523 deletions

View File

@ -37,7 +37,7 @@ void cpu_unregister_io_memory(int table_address);
struct MemoryRegionSection;
void cpu_register_physical_memory_log(struct MemoryRegionSection *section,
bool readable, bool readonly);
bool readonly);
void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size);
@ -121,6 +121,9 @@ static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
int dirty_flags);
extern const IORangeOps memory_region_iorange_ops;
#endif
#endif

893
exec.c

File diff suppressed because it is too large Load Diff

View File

@ -436,6 +436,14 @@ static bool vhost_section(MemoryRegionSection *section)
&& memory_region_is_ram(section->mr);
}
static void vhost_begin(MemoryListener *listener)
{
}
static void vhost_commit(MemoryListener *listener)
{
}
static void vhost_region_add(MemoryListener *listener,
MemoryRegionSection *section)
{
@ -476,6 +484,11 @@ static void vhost_region_del(MemoryListener *listener,
}
}
static void vhost_region_nop(MemoryListener *listener,
MemoryRegionSection *section)
{
}
static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
struct vhost_virtqueue *vq,
unsigned idx, bool enable_log)
@ -720,6 +733,18 @@ static void vhost_virtqueue_cleanup(struct vhost_dev *dev,
0, virtio_queue_get_desc_size(vdev, idx));
}
static void vhost_eventfd_add(MemoryListener *listener,
MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
}
static void vhost_eventfd_del(MemoryListener *listener,
MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
}
int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force)
{
uint64_t features;
@ -744,13 +769,19 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force)
hdev->features = features;
hdev->memory_listener = (MemoryListener) {
.begin = vhost_begin,
.commit = vhost_commit,
.region_add = vhost_region_add,
.region_del = vhost_region_del,
.region_nop = vhost_region_nop,
.log_start = vhost_log_start,
.log_stop = vhost_log_stop,
.log_sync = vhost_log_sync,
.log_global_start = vhost_log_global_start,
.log_global_stop = vhost_log_global_stop,
.eventfd_add = vhost_eventfd_add,
.eventfd_del = vhost_eventfd_del,
.priority = 10
};
hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
hdev->n_mem_sections = 0;
@ -759,7 +790,7 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force)
hdev->log_size = 0;
hdev->log_enabled = false;
hdev->started = false;
memory_listener_register(&hdev->memory_listener);
memory_listener_register(&hdev->memory_listener, NULL);
hdev->force = force;
return 0;
fail:

View File

@ -328,6 +328,7 @@ void portio_list_init(PortioList *piolist,
piolist->ports = callbacks;
piolist->nr = 0;
piolist->regions = g_new0(MemoryRegion *, n);
piolist->aliases = g_new0(MemoryRegion *, n);
piolist->address_space = NULL;
piolist->opaque = opaque;
piolist->name = name;
@ -336,6 +337,7 @@ void portio_list_init(PortioList *piolist,
void portio_list_destroy(PortioList *piolist)
{
g_free(piolist->regions);
g_free(piolist->aliases);
}
static void portio_list_add_1(PortioList *piolist,
@ -345,7 +347,7 @@ static void portio_list_add_1(PortioList *piolist,
{
MemoryRegionPortio *pio;
MemoryRegionOps *ops;
MemoryRegion *region;
MemoryRegion *region, *alias;
unsigned i;
/* Copy the sub-list and null-terminate it. */
@ -362,12 +364,20 @@ static void portio_list_add_1(PortioList *piolist,
ops->old_portio = pio;
region = g_new(MemoryRegion, 1);
alias = g_new(MemoryRegion, 1);
/*
* Use an alias so that the callback is called with an absolute address,
* rather than an offset relative to to start + off_low.
*/
memory_region_init_io(region, ops, piolist->opaque, piolist->name,
off_high - off_low);
memory_region_set_offset(region, start + off_low);
UINT64_MAX);
memory_region_init_alias(alias, piolist->name,
region, start + off_low, off_high - off_low);
memory_region_add_subregion(piolist->address_space,
start + off_low, region);
piolist->regions[piolist->nr++] = region;
start + off_low, alias);
piolist->regions[piolist->nr] = region;
piolist->aliases[piolist->nr] = alias;
++piolist->nr;
}
void portio_list_add(PortioList *piolist,
@ -409,15 +419,19 @@ void portio_list_add(PortioList *piolist,
void portio_list_del(PortioList *piolist)
{
MemoryRegion *mr;
MemoryRegion *mr, *alias;
unsigned i;
for (i = 0; i < piolist->nr; ++i) {
mr = piolist->regions[i];
memory_region_del_subregion(piolist->address_space, mr);
alias = piolist->aliases[i];
memory_region_del_subregion(piolist->address_space, alias);
memory_region_destroy(alias);
memory_region_destroy(mr);
g_free((MemoryRegionOps *)mr->ops);
g_free(mr);
g_free(alias);
piolist->regions[i] = NULL;
piolist->aliases[i] = NULL;
}
}

View File

@ -60,6 +60,7 @@ typedef struct PortioList {
struct MemoryRegion *address_space;
unsigned nr;
struct MemoryRegion **regions;
struct MemoryRegion **aliases;
void *opaque;
const char *name;
} PortioList;

View File

@ -28,6 +28,7 @@
#include "kvm.h"
#include "bswap.h"
#include "memory.h"
#include "exec-memory.h"
/* This check must be after config-host.h is included */
#ifdef CONFIG_EVENTFD
@ -674,6 +675,14 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add)
}
}
static void kvm_begin(MemoryListener *listener)
{
}
static void kvm_commit(MemoryListener *listener)
{
}
static void kvm_region_add(MemoryListener *listener,
MemoryRegionSection *section)
{
@ -686,6 +695,11 @@ static void kvm_region_del(MemoryListener *listener,
kvm_set_phys_mem(section, false);
}
static void kvm_region_nop(MemoryListener *listener,
MemoryRegionSection *section)
{
}
static void kvm_log_sync(MemoryListener *listener,
MemoryRegionSection *section)
{
@ -713,14 +727,95 @@ static void kvm_log_global_stop(struct MemoryListener *listener)
assert(r >= 0);
}
static void kvm_mem_ioeventfd_add(MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
int r;
assert(match_data && section->size == 4);
r = kvm_set_ioeventfd_mmio_long(fd, section->offset_within_address_space,
data, true);
if (r < 0) {
abort();
}
}
static void kvm_mem_ioeventfd_del(MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
int r;
r = kvm_set_ioeventfd_mmio_long(fd, section->offset_within_address_space,
data, false);
if (r < 0) {
abort();
}
}
static void kvm_io_ioeventfd_add(MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
int r;
assert(match_data && section->size == 2);
r = kvm_set_ioeventfd_pio_word(fd, section->offset_within_address_space,
data, true);
if (r < 0) {
abort();
}
}
static void kvm_io_ioeventfd_del(MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
int r;
r = kvm_set_ioeventfd_pio_word(fd, section->offset_within_address_space,
data, false);
if (r < 0) {
abort();
}
}
static void kvm_eventfd_add(MemoryListener *listener,
MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
if (section->address_space == get_system_memory()) {
kvm_mem_ioeventfd_add(section, match_data, data, fd);
} else {
kvm_io_ioeventfd_add(section, match_data, data, fd);
}
}
static void kvm_eventfd_del(MemoryListener *listener,
MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
if (section->address_space == get_system_memory()) {
kvm_mem_ioeventfd_del(section, match_data, data, fd);
} else {
kvm_io_ioeventfd_del(section, match_data, data, fd);
}
}
static MemoryListener kvm_memory_listener = {
.begin = kvm_begin,
.commit = kvm_commit,
.region_add = kvm_region_add,
.region_del = kvm_region_del,
.region_nop = kvm_region_nop,
.log_start = kvm_log_start,
.log_stop = kvm_log_stop,
.log_sync = kvm_log_sync,
.log_global_start = kvm_log_global_start,
.log_global_stop = kvm_log_global_stop,
.eventfd_add = kvm_eventfd_add,
.eventfd_del = kvm_eventfd_del,
.priority = 10,
};
static void kvm_handle_interrupt(CPUState *env, int mask)
@ -965,7 +1060,7 @@ int kvm_init(void)
}
kvm_state = s;
memory_listener_register(&kvm_memory_listener);
memory_listener_register(&kvm_memory_listener, NULL);
s->many_ioeventfds = kvm_check_many_ioeventfds();

328
memory.c
View File

@ -27,8 +27,8 @@ unsigned memory_region_transaction_depth = 0;
static bool memory_region_update_pending = false;
static bool global_dirty_log = false;
static QLIST_HEAD(, MemoryListener) memory_listeners
= QLIST_HEAD_INITIALIZER(memory_listeners);
static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
= QTAILQ_HEAD_INITIALIZER(memory_listeners);
typedef struct AddrRange AddrRange;
@ -82,6 +82,71 @@ static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2)
return addrrange_make(start, int128_sub(end, start));
}
enum ListenerDirection { Forward, Reverse };
static bool memory_listener_match(MemoryListener *listener,
MemoryRegionSection *section)
{
return !listener->address_space_filter
|| listener->address_space_filter == section->address_space;
}
#define MEMORY_LISTENER_CALL_GLOBAL(_callback, _direction, _args...) \
do { \
MemoryListener *_listener; \
\
switch (_direction) { \
case Forward: \
QTAILQ_FOREACH(_listener, &memory_listeners, link) { \
_listener->_callback(_listener, ##_args); \
} \
break; \
case Reverse: \
QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \
memory_listeners, link) { \
_listener->_callback(_listener, ##_args); \
} \
break; \
default: \
abort(); \
} \
} while (0)
#define MEMORY_LISTENER_CALL(_callback, _direction, _section, _args...) \
do { \
MemoryListener *_listener; \
\
switch (_direction) { \
case Forward: \
QTAILQ_FOREACH(_listener, &memory_listeners, link) { \
if (memory_listener_match(_listener, _section)) { \
_listener->_callback(_listener, _section, ##_args); \
} \
} \
break; \
case Reverse: \
QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \
memory_listeners, link) { \
if (memory_listener_match(_listener, _section)) { \
_listener->_callback(_listener, _section, ##_args); \
} \
} \
break; \
default: \
abort(); \
} \
} while (0)
#define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback) \
MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) { \
.mr = (fr)->mr, \
.address_space = (as)->root, \
.offset_within_region = (fr)->offset_in_region, \
.size = int128_get64((fr)->addr.size), \
.offset_within_address_space = int128_get64((fr)->addr.start), \
.readonly = (fr)->readonly, \
}))
struct CoalescedMemoryRange {
AddrRange addr;
QTAILQ_ENTRY(CoalescedMemoryRange) link;
@ -158,22 +223,12 @@ typedef struct AddressSpaceOps AddressSpaceOps;
/* A system address space - I/O, memory, etc. */
struct AddressSpace {
const AddressSpaceOps *ops;
MemoryRegion *root;
FlatView current_map;
int ioeventfd_nb;
MemoryRegionIoeventfd *ioeventfds;
};
struct AddressSpaceOps {
void (*range_add)(AddressSpace *as, FlatRange *fr);
void (*range_del)(AddressSpace *as, FlatRange *fr);
void (*log_start)(AddressSpace *as, FlatRange *fr);
void (*log_stop)(AddressSpace *as, FlatRange *fr);
void (*ioeventfd_add)(AddressSpace *as, MemoryRegionIoeventfd *fd);
void (*ioeventfd_del)(AddressSpace *as, MemoryRegionIoeventfd *fd);
};
#define FOR_EACH_FLAT_RANGE(var, view) \
for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
@ -305,74 +360,7 @@ static void access_with_adjusted_size(target_phys_addr_t addr,
}
}
static void as_memory_range_add(AddressSpace *as, FlatRange *fr)
{
MemoryRegionSection section = {
.mr = fr->mr,
.offset_within_address_space = int128_get64(fr->addr.start),
.offset_within_region = fr->offset_in_region,
.size = int128_get64(fr->addr.size),
};
cpu_register_physical_memory_log(&section, fr->readable, fr->readonly);
}
static void as_memory_range_del(AddressSpace *as, FlatRange *fr)
{
MemoryRegionSection section = {
.mr = &io_mem_unassigned,
.offset_within_address_space = int128_get64(fr->addr.start),
.offset_within_region = int128_get64(fr->addr.start),
.size = int128_get64(fr->addr.size),
};
cpu_register_physical_memory_log(&section, true, false);
}
static void as_memory_log_start(AddressSpace *as, FlatRange *fr)
{
}
static void as_memory_log_stop(AddressSpace *as, FlatRange *fr)
{
}
static void as_memory_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd)
{
int r;
assert(fd->match_data && int128_get64(fd->addr.size) == 4);
r = kvm_set_ioeventfd_mmio_long(fd->fd, int128_get64(fd->addr.start),
fd->data, true);
if (r < 0) {
abort();
}
}
static void as_memory_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd)
{
int r;
r = kvm_set_ioeventfd_mmio_long(fd->fd, int128_get64(fd->addr.start),
fd->data, false);
if (r < 0) {
abort();
}
}
static const AddressSpaceOps address_space_ops_memory = {
.range_add = as_memory_range_add,
.range_del = as_memory_range_del,
.log_start = as_memory_log_start,
.log_stop = as_memory_log_stop,
.ioeventfd_add = as_memory_ioeventfd_add,
.ioeventfd_del = as_memory_ioeventfd_del,
};
static AddressSpace address_space_memory = {
.ops = &address_space_ops_memory,
};
static AddressSpace address_space_memory;
static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset,
unsigned width, bool write)
@ -401,17 +389,17 @@ static void memory_region_iorange_read(IORange *iorange,
*data = ((uint64_t)1 << (width * 8)) - 1;
if (mrp) {
*data = mrp->read(mr->opaque, offset + mr->offset);
*data = mrp->read(mr->opaque, offset);
} else if (width == 2) {
mrp = find_portio(mr, offset, 1, false);
assert(mrp);
*data = mrp->read(mr->opaque, offset + mr->offset) |
(mrp->read(mr->opaque, offset + mr->offset + 1) << 8);
*data = mrp->read(mr->opaque, offset) |
(mrp->read(mr->opaque, offset + 1) << 8);
}
return;
}
*data = 0;
access_with_adjusted_size(offset + mr->offset, data, width,
access_with_adjusted_size(offset, data, width,
mr->ops->impl.min_access_size,
mr->ops->impl.max_access_size,
memory_region_read_accessor, mr);
@ -428,73 +416,27 @@ static void memory_region_iorange_write(IORange *iorange,
const MemoryRegionPortio *mrp = find_portio(mr, offset, width, true);
if (mrp) {
mrp->write(mr->opaque, offset + mr->offset, data);
mrp->write(mr->opaque, offset, data);
} else if (width == 2) {
mrp = find_portio(mr, offset, 1, false);
assert(mrp);
mrp->write(mr->opaque, offset + mr->offset, data & 0xff);
mrp->write(mr->opaque, offset + mr->offset + 1, data >> 8);
mrp->write(mr->opaque, offset, data & 0xff);
mrp->write(mr->opaque, offset + 1, data >> 8);
}
return;
}
access_with_adjusted_size(offset + mr->offset, &data, width,
access_with_adjusted_size(offset, &data, width,
mr->ops->impl.min_access_size,
mr->ops->impl.max_access_size,
memory_region_write_accessor, mr);
}
static const IORangeOps memory_region_iorange_ops = {
const IORangeOps memory_region_iorange_ops = {
.read = memory_region_iorange_read,
.write = memory_region_iorange_write,
};
static void as_io_range_add(AddressSpace *as, FlatRange *fr)
{
iorange_init(&fr->mr->iorange, &memory_region_iorange_ops,
int128_get64(fr->addr.start), int128_get64(fr->addr.size));
ioport_register(&fr->mr->iorange);
}
static void as_io_range_del(AddressSpace *as, FlatRange *fr)
{
isa_unassign_ioport(int128_get64(fr->addr.start),
int128_get64(fr->addr.size));
}
static void as_io_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd)
{
int r;
assert(fd->match_data && int128_get64(fd->addr.size) == 2);
r = kvm_set_ioeventfd_pio_word(fd->fd, int128_get64(fd->addr.start),
fd->data, true);
if (r < 0) {
abort();
}
}
static void as_io_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd)
{
int r;
r = kvm_set_ioeventfd_pio_word(fd->fd, int128_get64(fd->addr.start),
fd->data, false);
if (r < 0) {
abort();
}
}
static const AddressSpaceOps address_space_ops_io = {
.range_add = as_io_range_add,
.range_del = as_io_range_del,
.ioeventfd_add = as_io_ioeventfd_add,
.ioeventfd_del = as_io_ioeventfd_del,
};
static AddressSpace address_space_io = {
.ops = &address_space_ops_io,
};
static AddressSpace address_space_io;
static AddressSpace *memory_region_to_address_space(MemoryRegion *mr)
{
@ -621,6 +563,8 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
unsigned fds_old_nb)
{
unsigned iold, inew;
MemoryRegionIoeventfd *fd;
MemoryRegionSection section;
/* Generate a symmetric difference of the old and new fd sets, adding
* and deleting as necessary.
@ -632,13 +576,27 @@ static void address_space_add_del_ioeventfds(AddressSpace *as,
&& (inew == fds_new_nb
|| memory_region_ioeventfd_before(fds_old[iold],
fds_new[inew]))) {
as->ops->ioeventfd_del(as, &fds_old[iold]);
fd = &fds_old[iold];
section = (MemoryRegionSection) {
.address_space = as->root,
.offset_within_address_space = int128_get64(fd->addr.start),
.size = int128_get64(fd->addr.size),
};
MEMORY_LISTENER_CALL(eventfd_del, Forward, &section,
fd->match_data, fd->data, fd->fd);
++iold;
} else if (inew < fds_new_nb
&& (iold == fds_old_nb
|| memory_region_ioeventfd_before(fds_new[inew],
fds_old[iold]))) {
as->ops->ioeventfd_add(as, &fds_new[inew]);
fd = &fds_new[inew];
section = (MemoryRegionSection) {
.address_space = as->root,
.offset_within_address_space = int128_get64(fd->addr.start),
.size = int128_get64(fd->addr.size),
};
MEMORY_LISTENER_CALL(eventfd_add, Reverse, &section,
fd->match_data, fd->data, fd->fd);
++inew;
} else {
++iold;
@ -678,32 +636,6 @@ static void address_space_update_ioeventfds(AddressSpace *as)
as->ioeventfd_nb = ioeventfd_nb;
}
typedef void ListenerCallback(MemoryListener *listener,
MemoryRegionSection *mrs);
/* Want "void (&MemoryListener::*callback)(const MemoryRegionSection& s)" */
static void memory_listener_update_region(FlatRange *fr, AddressSpace *as,
size_t callback_offset)
{
MemoryRegionSection section = {
.mr = fr->mr,
.address_space = as->root,
.offset_within_region = fr->offset_in_region,
.size = int128_get64(fr->addr.size),
.offset_within_address_space = int128_get64(fr->addr.start),
};
MemoryListener *listener;
QLIST_FOREACH(listener, &memory_listeners, link) {
ListenerCallback *callback
= *(ListenerCallback **)((void *)listener + callback_offset);
callback(listener, &section);
}
}
#define MEMORY_LISTENER_UPDATE_REGION(fr, as, callback) \
memory_listener_update_region(fr, as, offsetof(MemoryListener, callback))
static void address_space_update_topology_pass(AddressSpace *as,
FlatView old_view,
FlatView new_view,
@ -736,8 +668,7 @@ static void address_space_update_topology_pass(AddressSpace *as,
/* In old, but (not in new, or in new but attributes changed). */
if (!adding) {
MEMORY_LISTENER_UPDATE_REGION(frold, as, region_del);
as->ops->range_del(as, frold);
MEMORY_LISTENER_UPDATE_REGION(frold, as, Reverse, region_del);
}
++iold;
@ -745,12 +676,11 @@ static void address_space_update_topology_pass(AddressSpace *as,
/* In both (logging may have changed) */
if (adding) {
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_nop);
if (frold->dirty_log_mask && !frnew->dirty_log_mask) {
MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_stop);
as->ops->log_stop(as, frnew);
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Reverse, log_stop);
} else if (frnew->dirty_log_mask && !frold->dirty_log_mask) {
as->ops->log_start(as, frnew);
MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_start);
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, log_start);
}
}
@ -760,8 +690,7 @@ static void address_space_update_topology_pass(AddressSpace *as,
/* In new */
if (adding) {
as->ops->range_add(as, frnew);
MEMORY_LISTENER_UPDATE_REGION(frnew, as, region_add);
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_add);
}
++inew;
@ -794,6 +723,8 @@ static void memory_region_update_topology(MemoryRegion *mr)
return;
}
MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
if (address_space_memory.root) {
address_space_update_topology(&address_space_memory);
}
@ -801,6 +732,8 @@ static void memory_region_update_topology(MemoryRegion *mr)
address_space_update_topology(&address_space_io);
}
MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
memory_region_update_pending = false;
}
@ -863,7 +796,6 @@ void memory_region_init(MemoryRegion *mr,
mr->size = int128_2_64();
}
mr->addr = 0;
mr->offset = 0;
mr->subpage = false;
mr->enabled = true;
mr->terminates = false;
@ -925,7 +857,7 @@ static uint64_t memory_region_dispatch_read1(MemoryRegion *mr,
}
/* FIXME: support unaligned access */
access_with_adjusted_size(addr + mr->offset, &data, size,
access_with_adjusted_size(addr, &data, size,
mr->ops->impl.min_access_size,
mr->ops->impl.max_access_size,
memory_region_read_accessor, mr);
@ -979,7 +911,7 @@ static void memory_region_dispatch_write(MemoryRegion *mr,
}
/* FIXME: support unaligned access */
access_with_adjusted_size(addr + mr->offset, &data, size,
access_with_adjusted_size(addr, &data, size,
mr->ops->impl.min_access_size,
mr->ops->impl.max_access_size,
memory_region_write_accessor, mr);
@ -1122,11 +1054,6 @@ bool memory_region_is_rom(MemoryRegion *mr)
return mr->ram && mr->readonly;
}
void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset)
{
mr->offset = offset;
}
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
{
uint8_t mask = 1 << client;
@ -1156,7 +1083,8 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
if (fr->mr == mr) {
MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, log_sync);
MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory,
Forward, log_sync);
}
}
}
@ -1474,6 +1402,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space,
fr->addr.start));
ret.size = int128_get64(range.size);
ret.offset_within_address_space = int128_get64(range.start);
ret.readonly = fr->readonly;
return ret;
}
@ -1483,30 +1412,20 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space)
FlatRange *fr;
FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
MEMORY_LISTENER_UPDATE_REGION(fr, as, log_sync);
MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
}
}
void memory_global_dirty_log_start(void)
{
MemoryListener *listener;
cpu_physical_memory_set_dirty_tracking(1);
global_dirty_log = true;
QLIST_FOREACH(listener, &memory_listeners, link) {
listener->log_global_start(listener);
}
MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward);
}
void memory_global_dirty_log_stop(void)
{
MemoryListener *listener;
global_dirty_log = false;
QLIST_FOREACH(listener, &memory_listeners, link) {
listener->log_global_stop(listener);
}
cpu_physical_memory_set_dirty_tracking(0);
MEMORY_LISTENER_CALL_GLOBAL(log_global_stop, Reverse);
}
static void listener_add_address_space(MemoryListener *listener,
@ -1524,21 +1443,36 @@ static void listener_add_address_space(MemoryListener *listener,
.offset_within_region = fr->offset_in_region,
.size = int128_get64(fr->addr.size),
.offset_within_address_space = int128_get64(fr->addr.start),
.readonly = fr->readonly,
};
listener->region_add(listener, &section);
}
}
void memory_listener_register(MemoryListener *listener)
void memory_listener_register(MemoryListener *listener, MemoryRegion *filter)
{
QLIST_INSERT_HEAD(&memory_listeners, listener, link);
MemoryListener *other = NULL;
listener->address_space_filter = filter;
if (QTAILQ_EMPTY(&memory_listeners)
|| listener->priority >= QTAILQ_LAST(&memory_listeners,
memory_listeners)->priority) {
QTAILQ_INSERT_TAIL(&memory_listeners, listener, link);
} else {
QTAILQ_FOREACH(other, &memory_listeners, link) {
if (listener->priority < other->priority) {
break;
}
}
QTAILQ_INSERT_BEFORE(other, listener, link);
}
listener_add_address_space(listener, &address_space_memory);
listener_add_address_space(listener, &address_space_io);
}
void memory_listener_unregister(MemoryListener *listener)
{
QLIST_REMOVE(listener, link);
QTAILQ_REMOVE(&memory_listeners, listener, link);
}
void set_system_memory_map(MemoryRegion *mr)

View File

@ -115,7 +115,6 @@ struct MemoryRegion {
MemoryRegion *parent;
Int128 size;
target_phys_addr_t addr;
target_phys_addr_t offset;
void (*destructor)(MemoryRegion *mr);
ram_addr_t ram_addr;
IORange iorange;
@ -161,6 +160,7 @@ typedef struct MemoryRegionSection MemoryRegionSection;
* @size: the size of the section; will not exceed @mr's boundaries
* @offset_within_address_space: the address of the first byte of the section
* relative to the region's address space
* @readonly: writes to this section are ignored
*/
struct MemoryRegionSection {
MemoryRegion *mr;
@ -168,6 +168,7 @@ struct MemoryRegionSection {
target_phys_addr_t offset_within_region;
uint64_t size;
target_phys_addr_t offset_within_address_space;
bool readonly;
};
typedef struct MemoryListener MemoryListener;
@ -179,14 +180,24 @@ typedef struct MemoryListener MemoryListener;
* Use with memory_listener_register() and memory_listener_unregister().
*/
struct MemoryListener {
void (*begin)(MemoryListener *listener);
void (*commit)(MemoryListener *listener);
void (*region_add)(MemoryListener *listener, MemoryRegionSection *section);
void (*region_del)(MemoryListener *listener, MemoryRegionSection *section);
void (*region_nop)(MemoryListener *listener, MemoryRegionSection *section);
void (*log_start)(MemoryListener *listener, MemoryRegionSection *section);
void (*log_stop)(MemoryListener *listener, MemoryRegionSection *section);
void (*log_sync)(MemoryListener *listener, MemoryRegionSection *section);
void (*log_global_start)(MemoryListener *listener);
void (*log_global_stop)(MemoryListener *listener);
QLIST_ENTRY(MemoryListener) link;
void (*eventfd_add)(MemoryListener *listener, MemoryRegionSection *section,
bool match_data, uint64_t data, int fd);
void (*eventfd_del)(MemoryListener *listener, MemoryRegionSection *section,
bool match_data, uint64_t data, int fd);
/* Lower = earlier (during add), later (during del) */
unsigned priority;
MemoryRegion *address_space_filter;
QTAILQ_ENTRY(MemoryListener) link;
};
/**
@ -358,14 +369,6 @@ bool memory_region_is_rom(MemoryRegion *mr);
*/
void *memory_region_get_ram_ptr(MemoryRegion *mr);
/**
* memory_region_set_offset: Sets an offset to be added to MemoryRegionOps
* callbacks.
*
* This function is deprecated and should not be used in new code.
*/
void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset);
/**
* memory_region_set_log: Turn dirty logging on or off for a region.
*
@ -686,8 +689,9 @@ void memory_region_transaction_commit(void);
* space
*
* @listener: an object containing the callbacks to be called
* @filter: if non-%NULL, only regions in this address space will be observed
*/
void memory_listener_register(MemoryListener *listener);
void memory_listener_register(MemoryListener *listener, MemoryRegion *filter);
/**
* memory_listener_unregister: undo the effect of memory_listener_register()

View File

@ -392,6 +392,14 @@ static void xen_set_memory(struct MemoryListener *listener,
}
}
static void xen_begin(MemoryListener *listener)
{
}
static void xen_commit(MemoryListener *listener)
{
}
static void xen_region_add(MemoryListener *listener,
MemoryRegionSection *section)
{
@ -404,6 +412,11 @@ static void xen_region_del(MemoryListener *listener,
xen_set_memory(listener, section, false);
}
static void xen_region_nop(MemoryListener *listener,
MemoryRegionSection *section)
{
}
static void xen_sync_dirty_bitmap(XenIOState *state,
target_phys_addr_t start_addr,
ram_addr_t size)
@ -485,14 +498,32 @@ static void xen_log_global_stop(MemoryListener *listener)
{
}
static void xen_eventfd_add(MemoryListener *listener,
MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
}
static void xen_eventfd_del(MemoryListener *listener,
MemoryRegionSection *section,
bool match_data, uint64_t data, int fd)
{
}
static MemoryListener xen_memory_listener = {
.begin = xen_begin,
.commit = xen_commit,
.region_add = xen_region_add,
.region_del = xen_region_del,
.region_nop = xen_region_nop,
.log_start = xen_log_start,
.log_stop = xen_log_stop,
.log_sync = xen_log_sync,
.log_global_start = xen_log_global_start,
.log_global_stop = xen_log_global_stop,
.eventfd_add = xen_eventfd_add,
.eventfd_del = xen_eventfd_del,
.priority = 10,
};
/* VCPU Operations, MMIO, IO ring ... */
@ -975,7 +1006,7 @@ int xen_hvm_init(void)
state->memory_listener = xen_memory_listener;
QLIST_INIT(&state->physmap);
memory_listener_register(&state->memory_listener);
memory_listener_register(&state->memory_listener, get_system_memory());
state->log_for_dirtybit = NULL;
/* Initialize backend core & drivers */