|
|
9ae3a8 |
From f13968b5693d5316f4904cdc32b4327b3974fcc6 Mon Sep 17 00:00:00 2001
|
|
|
9ae3a8 |
From: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
Date: Mon, 12 Aug 2013 15:59:39 +0200
|
|
|
9ae3a8 |
Subject: dump: populate guest_phys_blocks
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RH-Author: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
Message-id: <1376323180-12863-10-git-send-email-lersek@redhat.com>
|
|
|
9ae3a8 |
Patchwork-id: 53167
|
|
|
9ae3a8 |
O-Subject: [RHEL-7 qemu-kvm PATCH 09/10] dump: populate guest_phys_blocks
|
|
|
9ae3a8 |
Bugzilla: 981582
|
|
|
9ae3a8 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Radim Krcmar <rkrcmar@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
While the machine is paused, in guest_phys_blocks_append() we register a
|
|
|
9ae3a8 |
one-shot MemoryListener, solely for the initial collection of the valid
|
|
|
9ae3a8 |
guest-physical memory ranges that happens at listener registration time.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
For each range that is reported to guest_phys_blocks_region_add(), we
|
|
|
9ae3a8 |
attempt to merge the range with the preceding one.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Ranges can only be joined if they are contiguous in both guest-physical
|
|
|
9ae3a8 |
address space, and contiguous in host virtual address space.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
The "maximal" ranges that remain in the end constitute the guest-physical
|
|
|
9ae3a8 |
memory map that the dump will be based on.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Related RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=981582
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
|
|
|
9ae3a8 |
(cherry picked from commit c5d7f60f0614250bd925071e25220ce5958f75d0)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Conflicts:
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
memory_mapping.c
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
The conflicts are due to RHEL-7 not having:
|
|
|
9ae3a8 |
- upstream commit 182735ef ("cpu: Make first_cpu and next_cpu CPUState"),
|
|
|
9ae3a8 |
whose backport I rejected due to its many dependencies,
|
|
|
9ae3a8 |
- upstream commit 052e87b0 ("memory: make section size a 128-bit
|
|
|
9ae3a8 |
integer"), which seems quite intrusive, and to belong to the middle of a
|
|
|
9ae3a8 |
series.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/dump.c b/dump.c
|
|
|
9ae3a8 |
index 351233b..e6b7a00 100644
|
|
|
9ae3a8 |
--- a/dump.c
|
|
|
9ae3a8 |
+++ b/dump.c
|
|
|
9ae3a8 |
@@ -750,7 +750,7 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
|
|
|
9ae3a8 |
s->length = length;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
guest_phys_blocks_init(&s->guest_phys_blocks);
|
|
|
9ae3a8 |
- /* FILL LIST */
|
|
|
9ae3a8 |
+ guest_phys_blocks_append(&s->guest_phys_blocks);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
s->start = get_start_block(s);
|
|
|
9ae3a8 |
if (s->start == -1) {
|
|
|
9ae3a8 |
diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h
|
|
|
9ae3a8 |
index d2d06cd..b2d7d85 100644
|
|
|
9ae3a8 |
--- a/include/sysemu/memory_mapping.h
|
|
|
9ae3a8 |
+++ b/include/sysemu/memory_mapping.h
|
|
|
9ae3a8 |
@@ -66,6 +66,7 @@ void memory_mapping_list_init(MemoryMappingList *list);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
void guest_phys_blocks_free(GuestPhysBlockList *list);
|
|
|
9ae3a8 |
void guest_phys_blocks_init(GuestPhysBlockList *list);
|
|
|
9ae3a8 |
+void guest_phys_blocks_append(GuestPhysBlockList *list);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/memory_mapping.c b/memory_mapping.c
|
|
|
9ae3a8 |
index 78a9829..411aba6 100644
|
|
|
9ae3a8 |
--- a/memory_mapping.c
|
|
|
9ae3a8 |
+++ b/memory_mapping.c
|
|
|
9ae3a8 |
@@ -11,9 +11,15 @@
|
|
|
9ae3a8 |
*
|
|
|
9ae3a8 |
*/
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+#include <glib.h>
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
#include "cpu.h"
|
|
|
9ae3a8 |
#include "exec/cpu-all.h"
|
|
|
9ae3a8 |
#include "sysemu/memory_mapping.h"
|
|
|
9ae3a8 |
+#include "exec/memory.h"
|
|
|
9ae3a8 |
+#include "exec/address-spaces.h"
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+//#define DEBUG_GUEST_PHYS_REGION_ADD
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
|
|
|
9ae3a8 |
MemoryMapping *mapping)
|
|
|
9ae3a8 |
@@ -182,6 +188,84 @@ void guest_phys_blocks_init(GuestPhysBlockList *list)
|
|
|
9ae3a8 |
QTAILQ_INIT(&list->head);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+typedef struct GuestPhysListener {
|
|
|
9ae3a8 |
+ GuestPhysBlockList *list;
|
|
|
9ae3a8 |
+ MemoryListener listener;
|
|
|
9ae3a8 |
+} GuestPhysListener;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+static void guest_phys_blocks_region_add(MemoryListener *listener,
|
|
|
9ae3a8 |
+ MemoryRegionSection *section)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ GuestPhysListener *g;
|
|
|
9ae3a8 |
+ uint64_t section_size;
|
|
|
9ae3a8 |
+ hwaddr target_start, target_end;
|
|
|
9ae3a8 |
+ uint8_t *host_addr;
|
|
|
9ae3a8 |
+ GuestPhysBlock *predecessor;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* we only care about RAM */
|
|
|
9ae3a8 |
+ if (!memory_region_is_ram(section->mr)) {
|
|
|
9ae3a8 |
+ return;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ g = container_of(listener, GuestPhysListener, listener);
|
|
|
9ae3a8 |
+ section_size = section->size;
|
|
|
9ae3a8 |
+ target_start = section->offset_within_address_space;
|
|
|
9ae3a8 |
+ target_end = target_start + section_size;
|
|
|
9ae3a8 |
+ host_addr = memory_region_get_ram_ptr(section->mr) +
|
|
|
9ae3a8 |
+ section->offset_within_region;
|
|
|
9ae3a8 |
+ predecessor = NULL;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* find continuity in guest physical address space */
|
|
|
9ae3a8 |
+ if (!QTAILQ_EMPTY(&g->list->head)) {
|
|
|
9ae3a8 |
+ hwaddr predecessor_size;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ predecessor = QTAILQ_LAST(&g->list->head, GuestPhysBlockHead);
|
|
|
9ae3a8 |
+ predecessor_size = predecessor->target_end - predecessor->target_start;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* the memory API guarantees monotonically increasing traversal */
|
|
|
9ae3a8 |
+ g_assert(predecessor->target_end <= target_start);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* we want continuity in both guest-physical and host-virtual memory */
|
|
|
9ae3a8 |
+ if (predecessor->target_end < target_start ||
|
|
|
9ae3a8 |
+ predecessor->host_addr + predecessor_size != host_addr) {
|
|
|
9ae3a8 |
+ predecessor = NULL;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (predecessor == NULL) {
|
|
|
9ae3a8 |
+ /* isolated mapping, allocate it and add it to the list */
|
|
|
9ae3a8 |
+ GuestPhysBlock *block = g_malloc0(sizeof *block);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ block->target_start = target_start;
|
|
|
9ae3a8 |
+ block->target_end = target_end;
|
|
|
9ae3a8 |
+ block->host_addr = host_addr;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ QTAILQ_INSERT_TAIL(&g->list->head, block, next);
|
|
|
9ae3a8 |
+ ++g->list->num;
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ /* expand predecessor until @target_end; predecessor's start doesn't
|
|
|
9ae3a8 |
+ * change
|
|
|
9ae3a8 |
+ */
|
|
|
9ae3a8 |
+ predecessor->target_end = target_end;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+#ifdef DEBUG_GUEST_PHYS_REGION_ADD
|
|
|
9ae3a8 |
+ fprintf(stderr, "%s: target_start=" TARGET_FMT_plx " target_end="
|
|
|
9ae3a8 |
+ TARGET_FMT_plx ": %s (count: %u)\n", __FUNCTION__, target_start,
|
|
|
9ae3a8 |
+ target_end, predecessor ? "joined" : "added", g->list->num);
|
|
|
9ae3a8 |
+#endif
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+void guest_phys_blocks_append(GuestPhysBlockList *list)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ GuestPhysListener g = { 0 };
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ g.list = list;
|
|
|
9ae3a8 |
+ g.listener.region_add = &guest_phys_blocks_region_add;
|
|
|
9ae3a8 |
+ memory_listener_register(&g.listener, &address_space_memory);
|
|
|
9ae3a8 |
+ memory_listener_unregister(&g.listener);
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
static CPUArchState *find_paging_enabled_cpu(CPUArchState *start_cpu)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
CPUArchState *env;
|