| From 0c26814e42d1090b3ad3a20ca97b5a74accee7e9 Mon Sep 17 00:00:00 2001 |
| From: Laszlo Ersek <lersek@redhat.com> |
| Date: Mon, 12 Aug 2013 15:59:38 +0200 |
| Subject: dump: introduce GuestPhysBlockList |
| |
| RH-Author: Laszlo Ersek <lersek@redhat.com> |
| Message-id: <1376323180-12863-9-git-send-email-lersek@redhat.com> |
| Patchwork-id: 53166 |
| O-Subject: [RHEL-7 qemu-kvm PATCH 08/10] dump: introduce GuestPhysBlockList |
| Bugzilla: 981582 |
| RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com> |
| RH-Acked-by: Radim Krcmar <rkrcmar@redhat.com> |
| RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com> |
| |
| The vmcore must use physical addresses that are visible to the guest, not |
| addresses that point into linear RAMBlocks. As first step, introduce the |
| list type into which we'll collect the physical mappings in effect at the |
| time of the dump. |
| |
| 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> |
| (cherry picked from commit 5ee163e8ea2fb6610339f494e039159e08a69066) |
| |
| Conflicts: |
| |
| dump.c |
| memory_mapping.c |
| |
| The conflicts are due to RHEL-7 not having upstream commit 182735ef ("cpu: |
| Make first_cpu and next_cpu CPUState"), whose backport I rejected due to |
| its many dependencies. |
| |
| diff --git a/dump.c b/dump.c |
| index cbfad1c..351233b 100644 |
| |
| |
| @@ -59,6 +59,7 @@ static uint64_t cpu_convert_to_target64(uint64_t val, int endian) |
| } |
| |
| typedef struct DumpState { |
| + GuestPhysBlockList guest_phys_blocks; |
| ArchDumpInfo dump_info; |
| MemoryMappingList list; |
| uint16_t phdr_num; |
| @@ -81,6 +82,7 @@ static int dump_cleanup(DumpState *s) |
| { |
| int ret = 0; |
| |
| + guest_phys_blocks_free(&s->guest_phys_blocks); |
| memory_mapping_list_free(&s->list); |
| if (s->fd != -1) { |
| close(s->fd); |
| @@ -732,31 +734,34 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, |
| s->resume = false; |
| } |
| |
| + /* If we use KVM, we should synchronize the registers before we get dump |
| + * info or physmap info. |
| + */ |
| + cpu_synchronize_all_states(); |
| + nr_cpus = 0; |
| + for (env = first_cpu; env != NULL; env = env->next_cpu) { |
| + nr_cpus++; |
| + } |
| + |
| s->errp = errp; |
| s->fd = fd; |
| s->has_filter = has_filter; |
| s->begin = begin; |
| s->length = length; |
| + |
| + guest_phys_blocks_init(&s->guest_phys_blocks); |
| + /* FILL LIST */ |
| + |
| s->start = get_start_block(s); |
| if (s->start == -1) { |
| error_set(errp, QERR_INVALID_PARAMETER, "begin"); |
| goto cleanup; |
| } |
| |
| - /* |
| - * get dump info: endian, class and architecture. |
| + /* get dump info: endian, class and architecture. |
| * If the target architecture is not supported, cpu_get_dump_info() will |
| * return -1. |
| - * |
| - * If we use KVM, we should synchronize the registers before we get dump |
| - * info. |
| */ |
| - cpu_synchronize_all_states(); |
| - nr_cpus = 0; |
| - for (env = first_cpu; env != NULL; env = env->next_cpu) { |
| - nr_cpus++; |
| - } |
| - |
| ret = cpu_get_dump_info(&s->dump_info); |
| if (ret < 0) { |
| error_set(errp, QERR_UNSUPPORTED); |
| @@ -831,6 +836,8 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter, |
| return 0; |
| |
| cleanup: |
| + guest_phys_blocks_free(&s->guest_phys_blocks); |
| + |
| if (s->resume) { |
| vm_start(); |
| } |
| @@ -878,7 +885,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin, |
| return; |
| } |
| |
| - s = g_malloc(sizeof(DumpState)); |
| + s = g_malloc0(sizeof(DumpState)); |
| |
| ret = dump_init(s, fd, paging, has_begin, begin, length, errp); |
| if (ret < 0) { |
| diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h |
| index 6dfb68d..d2d06cd 100644 |
| |
| |
| @@ -17,6 +17,25 @@ |
| #include "qemu/queue.h" |
| #include "qemu/typedefs.h" |
| |
| +typedef struct GuestPhysBlock { |
| + /* visible to guest, reflects PCI hole, etc */ |
| + hwaddr target_start; |
| + |
| + /* implies size */ |
| + hwaddr target_end; |
| + |
| + /* points into host memory */ |
| + uint8_t *host_addr; |
| + |
| + QTAILQ_ENTRY(GuestPhysBlock) next; |
| +} GuestPhysBlock; |
| + |
| +/* point-in-time snapshot of guest-visible physical mappings */ |
| +typedef struct GuestPhysBlockList { |
| + unsigned num; |
| + QTAILQ_HEAD(GuestPhysBlockHead, GuestPhysBlock) head; |
| +} GuestPhysBlockList; |
| + |
| /* The physical and virtual address in the memory mapping are contiguous. */ |
| typedef struct MemoryMapping { |
| hwaddr phys_addr; |
| @@ -45,6 +64,9 @@ void memory_mapping_list_free(MemoryMappingList *list); |
| |
| void memory_mapping_list_init(MemoryMappingList *list); |
| |
| +void guest_phys_blocks_free(GuestPhysBlockList *list); |
| +void guest_phys_blocks_init(GuestPhysBlockList *list); |
| + |
| void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp); |
| |
| /* get guest's memory mapping without do paging(virtual address is 0). */ |
| diff --git a/memory_mapping.c b/memory_mapping.c |
| index 5634f81..78a9829 100644 |
| |
| |
| @@ -165,6 +165,23 @@ void memory_mapping_list_init(MemoryMappingList *list) |
| QTAILQ_INIT(&list->head); |
| } |
| |
| +void guest_phys_blocks_free(GuestPhysBlockList *list) |
| +{ |
| + GuestPhysBlock *p, *q; |
| + |
| + QTAILQ_FOREACH_SAFE(p, &list->head, next, q) { |
| + QTAILQ_REMOVE(&list->head, p, next); |
| + g_free(p); |
| + } |
| + list->num = 0; |
| +} |
| + |
| +void guest_phys_blocks_init(GuestPhysBlockList *list) |
| +{ |
| + list->num = 0; |
| + QTAILQ_INIT(&list->head); |
| +} |
| + |
| static CPUArchState *find_paging_enabled_cpu(CPUArchState *start_cpu) |
| { |
| CPUArchState *env; |