aboutsummaryrefslogtreecommitdiff
path: root/softmmu
diff options
context:
space:
mode:
Diffstat (limited to 'softmmu')
-rw-r--r--softmmu/cpus.c2
-rw-r--r--softmmu/memory.c110
-rw-r--r--softmmu/physmem.c108
-rw-r--r--softmmu/trace-events4
4 files changed, 188 insertions, 36 deletions
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index c3caaeb26e..071085f840 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -325,7 +325,7 @@ static void sigbus_reraise(void)
sigaddset(&set, SIGBUS);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
}
- perror("Failed to re-raise SIGBUS!\n");
+ perror("Failed to re-raise SIGBUS!");
abort();
}
diff --git a/softmmu/memory.c b/softmmu/memory.c
index f0161515e9..bfedaf9c4d 100644
--- a/softmmu/memory.c
+++ b/softmmu/memory.c
@@ -442,7 +442,8 @@ static MemTxResult memory_region_read_accessor(MemoryRegion *mr,
trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size);
} else if (trace_event_get_state_backends(TRACE_MEMORY_REGION_OPS_READ)) {
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
- trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size);
+ trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size,
+ memory_region_name(mr));
}
memory_region_shift_read_access(value, shift, mask, tmp);
return MEMTX_OK;
@@ -464,7 +465,8 @@ static MemTxResult memory_region_read_with_attrs_accessor(MemoryRegion *mr,
trace_memory_region_subpage_read(get_cpu_index(), mr, addr, tmp, size);
} else if (trace_event_get_state_backends(TRACE_MEMORY_REGION_OPS_READ)) {
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
- trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size);
+ trace_memory_region_ops_read(get_cpu_index(), mr, abs_addr, tmp, size,
+ memory_region_name(mr));
}
memory_region_shift_read_access(value, shift, mask, tmp);
return r;
@@ -484,7 +486,8 @@ static MemTxResult memory_region_write_accessor(MemoryRegion *mr,
trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size);
} else if (trace_event_get_state_backends(TRACE_MEMORY_REGION_OPS_WRITE)) {
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
- trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size);
+ trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size,
+ memory_region_name(mr));
}
mr->ops->write(mr->opaque, addr, tmp, size);
return MEMTX_OK;
@@ -504,7 +507,8 @@ static MemTxResult memory_region_write_with_attrs_accessor(MemoryRegion *mr,
trace_memory_region_subpage_write(get_cpu_index(), mr, addr, tmp, size);
} else if (trace_event_get_state_backends(TRACE_MEMORY_REGION_OPS_WRITE)) {
hwaddr abs_addr = memory_region_to_absolute_addr(mr, addr);
- trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size);
+ trace_memory_region_ops_write(get_cpu_index(), mr, abs_addr, tmp, size,
+ memory_region_name(mr));
}
return mr->ops->write_with_attrs(mr->opaque, addr, tmp, size, attrs);
}
@@ -2027,6 +2031,70 @@ int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr)
return imrc->num_indexes(iommu_mr);
}
+RamDiscardManager *memory_region_get_ram_discard_manager(MemoryRegion *mr)
+{
+ if (!memory_region_is_mapped(mr) || !memory_region_is_ram(mr)) {
+ return NULL;
+ }
+ return mr->rdm;
+}
+
+void memory_region_set_ram_discard_manager(MemoryRegion *mr,
+ RamDiscardManager *rdm)
+{
+ g_assert(memory_region_is_ram(mr) && !memory_region_is_mapped(mr));
+ g_assert(!rdm || !mr->rdm);
+ mr->rdm = rdm;
+}
+
+uint64_t ram_discard_manager_get_min_granularity(const RamDiscardManager *rdm,
+ const MemoryRegion *mr)
+{
+ RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
+
+ g_assert(rdmc->get_min_granularity);
+ return rdmc->get_min_granularity(rdm, mr);
+}
+
+bool ram_discard_manager_is_populated(const RamDiscardManager *rdm,
+ const MemoryRegionSection *section)
+{
+ RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
+
+ g_assert(rdmc->is_populated);
+ return rdmc->is_populated(rdm, section);
+}
+
+int ram_discard_manager_replay_populated(const RamDiscardManager *rdm,
+ MemoryRegionSection *section,
+ ReplayRamPopulate replay_fn,
+ void *opaque)
+{
+ RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
+
+ g_assert(rdmc->replay_populated);
+ return rdmc->replay_populated(rdm, section, replay_fn, opaque);
+}
+
+void ram_discard_manager_register_listener(RamDiscardManager *rdm,
+ RamDiscardListener *rdl,
+ MemoryRegionSection *section)
+{
+ RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
+
+ g_assert(rdmc->register_listener);
+ rdmc->register_listener(rdm, rdl, section);
+}
+
+void ram_discard_manager_unregister_listener(RamDiscardManager *rdm,
+ RamDiscardListener *rdl)
+{
+ RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_GET_CLASS(rdm);
+
+ g_assert(rdmc->unregister_listener);
+ rdmc->unregister_listener(rdm, rdl);
+}
+
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
{
uint8_t mask = 1 << client;
@@ -2637,6 +2705,33 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr,
return ret;
}
+MemoryRegionSection *memory_region_section_new_copy(MemoryRegionSection *s)
+{
+ MemoryRegionSection *tmp = g_new(MemoryRegionSection, 1);
+
+ *tmp = *s;
+ if (tmp->mr) {
+ memory_region_ref(tmp->mr);
+ }
+ if (tmp->fv) {
+ bool ret = flatview_ref(tmp->fv);
+
+ g_assert(ret);
+ }
+ return tmp;
+}
+
+void memory_region_section_free_copy(MemoryRegionSection *s)
+{
+ if (s->fv) {
+ flatview_unref(s->fv);
+ }
+ if (s->mr) {
+ memory_region_unref(s->mr);
+ }
+ g_free(s);
+}
+
bool memory_region_present(MemoryRegion *container, hwaddr addr)
{
MemoryRegion *mr;
@@ -3320,10 +3415,17 @@ static const TypeInfo iommu_memory_region_info = {
.abstract = true,
};
+static const TypeInfo ram_discard_manager_info = {
+ .parent = TYPE_INTERFACE,
+ .name = TYPE_RAM_DISCARD_MANAGER,
+ .class_size = sizeof(RamDiscardManagerClass),
+};
+
static void memory_register_types(void)
{
type_register_static(&memory_region_info);
type_register_static(&iommu_memory_region_info);
+ type_register_static(&ram_discard_manager_info);
}
type_init(memory_register_types)
diff --git a/softmmu/physmem.c b/softmmu/physmem.c
index 9b171c9dbe..3c1912a1a0 100644
--- a/softmmu/physmem.c
+++ b/softmmu/physmem.c
@@ -3684,56 +3684,106 @@ void mtree_print_dispatch(AddressSpaceDispatch *d, MemoryRegion *root)
}
}
-/*
- * If positive, discarding RAM is disabled. If negative, discarding RAM is
- * required to work and cannot be disabled.
- */
-static int ram_block_discard_disabled;
+/* Require any discards to work. */
+static unsigned int ram_block_discard_required_cnt;
+/* Require only coordinated discards to work. */
+static unsigned int ram_block_coordinated_discard_required_cnt;
+/* Disable any discards. */
+static unsigned int ram_block_discard_disabled_cnt;
+/* Disable only uncoordinated discards. */
+static unsigned int ram_block_uncoordinated_discard_disabled_cnt;
+static QemuMutex ram_block_discard_disable_mutex;
+
+static void ram_block_discard_disable_mutex_lock(void)
+{
+ static gsize initialized;
+
+ if (g_once_init_enter(&initialized)) {
+ qemu_mutex_init(&ram_block_discard_disable_mutex);
+ g_once_init_leave(&initialized, 1);
+ }
+ qemu_mutex_lock(&ram_block_discard_disable_mutex);
+}
+
+static void ram_block_discard_disable_mutex_unlock(void)
+{
+ qemu_mutex_unlock(&ram_block_discard_disable_mutex);
+}
int ram_block_discard_disable(bool state)
{
- int old;
+ int ret = 0;
+ ram_block_discard_disable_mutex_lock();
if (!state) {
- qatomic_dec(&ram_block_discard_disabled);
- return 0;
+ ram_block_discard_disabled_cnt--;
+ } else if (ram_block_discard_required_cnt ||
+ ram_block_coordinated_discard_required_cnt) {
+ ret = -EBUSY;
+ } else {
+ ram_block_discard_disabled_cnt++;
}
+ ram_block_discard_disable_mutex_unlock();
+ return ret;
+}
- do {
- old = qatomic_read(&ram_block_discard_disabled);
- if (old < 0) {
- return -EBUSY;
- }
- } while (qatomic_cmpxchg(&ram_block_discard_disabled,
- old, old + 1) != old);
- return 0;
+int ram_block_uncoordinated_discard_disable(bool state)
+{
+ int ret = 0;
+
+ ram_block_discard_disable_mutex_lock();
+ if (!state) {
+ ram_block_uncoordinated_discard_disabled_cnt--;
+ } else if (ram_block_discard_required_cnt) {
+ ret = -EBUSY;
+ } else {
+ ram_block_uncoordinated_discard_disabled_cnt++;
+ }
+ ram_block_discard_disable_mutex_unlock();
+ return ret;
}
int ram_block_discard_require(bool state)
{
- int old;
+ int ret = 0;
+ ram_block_discard_disable_mutex_lock();
if (!state) {
- qatomic_inc(&ram_block_discard_disabled);
- return 0;
+ ram_block_discard_required_cnt--;
+ } else if (ram_block_discard_disabled_cnt ||
+ ram_block_uncoordinated_discard_disabled_cnt) {
+ ret = -EBUSY;
+ } else {
+ ram_block_discard_required_cnt++;
}
+ ram_block_discard_disable_mutex_unlock();
+ return ret;
+}
- do {
- old = qatomic_read(&ram_block_discard_disabled);
- if (old > 0) {
- return -EBUSY;
- }
- } while (qatomic_cmpxchg(&ram_block_discard_disabled,
- old, old - 1) != old);
- return 0;
+int ram_block_coordinated_discard_require(bool state)
+{
+ int ret = 0;
+
+ ram_block_discard_disable_mutex_lock();
+ if (!state) {
+ ram_block_coordinated_discard_required_cnt--;
+ } else if (ram_block_discard_disabled_cnt) {
+ ret = -EBUSY;
+ } else {
+ ram_block_coordinated_discard_required_cnt++;
+ }
+ ram_block_discard_disable_mutex_unlock();
+ return ret;
}
bool ram_block_discard_is_disabled(void)
{
- return qatomic_read(&ram_block_discard_disabled) > 0;
+ return qatomic_read(&ram_block_discard_disabled_cnt) ||
+ qatomic_read(&ram_block_uncoordinated_discard_disabled_cnt);
}
bool ram_block_discard_is_required(void)
{
- return qatomic_read(&ram_block_discard_disabled) < 0;
+ return qatomic_read(&ram_block_discard_required_cnt) ||
+ qatomic_read(&ram_block_coordinated_discard_required_cnt);
}
diff --git a/softmmu/trace-events b/softmmu/trace-events
index d18ac41e4e..7b278590a0 100644
--- a/softmmu/trace-events
+++ b/softmmu/trace-events
@@ -9,8 +9,8 @@ cpu_in(unsigned int addr, char size, unsigned int val) "addr 0x%x(%c) value %u"
cpu_out(unsigned int addr, char size, unsigned int val) "addr 0x%x(%c) value %u"
# memory.c
-memory_region_ops_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
-memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"
+memory_region_ops_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size, const char *name) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u name '%s'"
+memory_region_ops_write(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size, const char *name) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u name '%s'"
memory_region_subpage_read(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_subpage_write(int cpu_index, void *mr, uint64_t offset, uint64_t value, unsigned size) "cpu %d mr %p offset 0x%"PRIx64" value 0x%"PRIx64" size %u"
memory_region_ram_device_read(int cpu_index, void *mr, uint64_t addr, uint64_t value, unsigned size) "cpu %d mr %p addr 0x%"PRIx64" value 0x%"PRIx64" size %u"