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>
This commit is contained in:
parent
5ee163e8ea
commit
c5d7f60f06
2
dump.c
2
dump.c
@ -746,7 +746,7 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
|
|||||||
s->length = length;
|
s->length = length;
|
||||||
|
|
||||||
guest_phys_blocks_init(&s->guest_phys_blocks);
|
guest_phys_blocks_init(&s->guest_phys_blocks);
|
||||||
/* FILL LIST */
|
guest_phys_blocks_append(&s->guest_phys_blocks);
|
||||||
|
|
||||||
s->start = get_start_block(s);
|
s->start = get_start_block(s);
|
||||||
if (s->start == -1) {
|
if (s->start == -1) {
|
||||||
|
@ -66,6 +66,7 @@ void memory_mapping_list_init(MemoryMappingList *list);
|
|||||||
|
|
||||||
void guest_phys_blocks_free(GuestPhysBlockList *list);
|
void guest_phys_blocks_free(GuestPhysBlockList *list);
|
||||||
void guest_phys_blocks_init(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);
|
void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp);
|
||||||
|
|
||||||
|
@ -11,9 +11,15 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/cpu-all.h"
|
#include "exec/cpu-all.h"
|
||||||
#include "sysemu/memory_mapping.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,
|
static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
|
||||||
MemoryMapping *mapping)
|
MemoryMapping *mapping)
|
||||||
@ -182,6 +188,84 @@ void guest_phys_blocks_init(GuestPhysBlockList *list)
|
|||||||
QTAILQ_INIT(&list->head);
|
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)
|
static CPUState *find_paging_enabled_cpu(CPUState *start_cpu)
|
||||||
{
|
{
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
|
Loading…
Reference in New Issue
Block a user