aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaszlo Ersek <lersek@redhat.com>2013-08-06 12:37:10 +0200
committerLuiz Capitulino <lcapitulino@redhat.com>2013-08-08 11:01:46 -0400
commitc5d7f60f0614250bd925071e25220ce5958f75d0 (patch)
tree893fa3598476b807559ae2ab76e2db8da433b75c
parent5ee163e8ea2fb6610339f494e039159e08a69066 (diff)
downloadqemu-c5d7f60f0614250bd925071e25220ce5958f75d0.zip
qemu-c5d7f60f0614250bd925071e25220ce5958f75d0.tar.gz
qemu-c5d7f60f0614250bd925071e25220ce5958f75d0.tar.bz2
dump: populate guest_phys_blocks
While the machine is paused, in guest_phys_blocks_append() we register a one-shot MemoryListener, solely for the initial collection of the valid guest-physical memory ranges that happens at listener registration time. For each range that is reported to guest_phys_blocks_region_add(), we attempt to merge the range with the preceding one. Ranges can only be joined if they are contiguous in both guest-physical address space, and contiguous in host virtual address space. The "maximal" ranges that remain in the end constitute the guest-physical memory map that the dump will be based on. Related RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=981582 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
-rw-r--r--dump.c2
-rw-r--r--include/sysemu/memory_mapping.h1
-rw-r--r--memory_mapping.c84
3 files changed, 86 insertions, 1 deletions
diff --git a/dump.c b/dump.c
index 716fb1d..3fa33fc 100644
--- a/dump.c
+++ b/dump.c
@@ -746,7 +746,7 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
s->length = length;
guest_phys_blocks_init(&s->guest_phys_blocks);
- /* FILL LIST */
+ guest_phys_blocks_append(&s->guest_phys_blocks);
s->start = get_start_block(s);
if (s->start == -1) {
diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h
index d2d06cd..b2d7d85 100644
--- a/include/sysemu/memory_mapping.h
+++ b/include/sysemu/memory_mapping.h
@@ -66,6 +66,7 @@ void memory_mapping_list_init(MemoryMappingList *list);
void guest_phys_blocks_free(GuestPhysBlockList *list);
void guest_phys_blocks_init(GuestPhysBlockList *list);
+void guest_phys_blocks_append(GuestPhysBlockList *list);
void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp);
diff --git a/memory_mapping.c b/memory_mapping.c
index c70505b..876f5aa7 100644
--- a/memory_mapping.c
+++ b/memory_mapping.c
@@ -11,9 +11,15 @@
*
*/
+#include <glib.h>
+
#include "cpu.h"
#include "exec/cpu-all.h"
#include "sysemu/memory_mapping.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG_GUEST_PHYS_REGION_ADD
static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
MemoryMapping *mapping)
@@ -182,6 +188,84 @@ void guest_phys_blocks_init(GuestPhysBlockList *list)
QTAILQ_INIT(&list->head);
}
+typedef struct GuestPhysListener {
+ GuestPhysBlockList *list;
+ MemoryListener listener;
+} GuestPhysListener;
+
+static void guest_phys_blocks_region_add(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ GuestPhysListener *g;
+ uint64_t section_size;
+ hwaddr target_start, target_end;
+ uint8_t *host_addr;
+ GuestPhysBlock *predecessor;
+
+ /* we only care about RAM */
+ if (!memory_region_is_ram(section->mr)) {
+ return;
+ }
+
+ g = container_of(listener, GuestPhysListener, listener);
+ section_size = int128_get64(section->size);
+ target_start = section->offset_within_address_space;
+ target_end = target_start + section_size;
+ host_addr = memory_region_get_ram_ptr(section->mr) +
+ section->offset_within_region;
+ predecessor = NULL;
+
+ /* find continuity in guest physical address space */
+ if (!QTAILQ_EMPTY(&g->list->head)) {
+ hwaddr predecessor_size;
+
+ predecessor = QTAILQ_LAST(&g->list->head, GuestPhysBlockHead);
+ predecessor_size = predecessor->target_end - predecessor->target_start;
+
+ /* the memory API guarantees monotonically increasing traversal */
+ g_assert(predecessor->target_end <= target_start);
+
+ /* we want continuity in both guest-physical and host-virtual memory */
+ if (predecessor->target_end < target_start ||
+ predecessor->host_addr + predecessor_size != host_addr) {
+ predecessor = NULL;
+ }
+ }
+
+ if (predecessor == NULL) {
+ /* isolated mapping, allocate it and add it to the list */
+ GuestPhysBlock *block = g_malloc0(sizeof *block);
+
+ block->target_start = target_start;
+ block->target_end = target_end;
+ block->host_addr = host_addr;
+
+ QTAILQ_INSERT_TAIL(&g->list->head, block, next);
+ ++g->list->num;
+ } else {
+ /* expand predecessor until @target_end; predecessor's start doesn't
+ * change
+ */
+ predecessor->target_end = target_end;
+ }
+
+#ifdef DEBUG_GUEST_PHYS_REGION_ADD
+ fprintf(stderr, "%s: target_start=" TARGET_FMT_plx " target_end="
+ TARGET_FMT_plx ": %s (count: %u)\n", __FUNCTION__, target_start,
+ target_end, predecessor ? "joined" : "added", g->list->num);
+#endif
+}
+
+void guest_phys_blocks_append(GuestPhysBlockList *list)
+{
+ GuestPhysListener g = { 0 };
+
+ g.list = list;
+ g.listener.region_add = &guest_phys_blocks_region_add;
+ memory_listener_register(&g.listener, &address_space_memory);
+ memory_listener_unregister(&g.listener);
+}
+
static CPUState *find_paging_enabled_cpu(CPUState *start_cpu)
{
CPUState *cpu;