Blame SOURCES/kvm-dump-rebase-from-host-private-RAMBlock-offsets-to-guest-physical-addresses.patch

9ae3a8
From c67daf48e19c0a73c933d09a4c748cfda8d6d3f2 Mon Sep 17 00:00:00 2001
9ae3a8
From: Laszlo Ersek <lersek@redhat.com>
9ae3a8
Date: Mon, 12 Aug 2013 15:59:40 +0200
9ae3a8
Subject: dump: rebase from host-private RAMBlock offsets to guest-physical addresses
9ae3a8
9ae3a8
RH-Author: Laszlo Ersek <lersek@redhat.com>
9ae3a8
Message-id: <1376323180-12863-11-git-send-email-lersek@redhat.com>
9ae3a8
Patchwork-id: 53168
9ae3a8
O-Subject: [RHEL-7 qemu-kvm PATCH 10/10] dump: rebase from host-private RAMBlock offsets to guest-physical addresses
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
RAMBlock.offset                   --> GuestPhysBlock.target_start
9ae3a8
RAMBlock.offset + RAMBlock.length --> GuestPhysBlock.target_end
9ae3a8
RAMBlock.length                   --> GuestPhysBlock.target_end -
9ae3a8
                                      GuestPhysBlock.target_start
9ae3a8
9ae3a8
"GuestPhysBlock.host_addr" is only used when writing the dump contents.
9ae3a8
9ae3a8
This patch enables "crash" to work with the vmcore by rebasing the vmcore
9ae3a8
from the left side of the following diagram to the right side:
9ae3a8
9ae3a8
host-private
9ae3a8
offset
9ae3a8
relative
9ae3a8
to ram_addr   RAMBlock                  guest-visible paddrs
9ae3a8
            0 +-------------------+.....+-------------------+ 0
9ae3a8
              |         ^         |     |        ^          |
9ae3a8
              |       640 KB      |     |      640 KB       |
9ae3a8
              |         v         |     |        v          |
9ae3a8
  0x0000a0000 +-------------------+.....+-------------------+ 0x0000a0000
9ae3a8
              |         ^         |     |XXXXXXXXXXXXXXXXXXX|
9ae3a8
              |       384 KB      |     |XXXXXXXXXXXXXXXXXXX|
9ae3a8
              |         v         |     |XXXXXXXXXXXXXXXXXXX|
9ae3a8
  0x000100000 +-------------------+.....+-------------------+ 0x000100000
9ae3a8
              |         ^         |     |        ^          |
9ae3a8
              |       3583 MB     |     |      3583 MB      |
9ae3a8
              |         v         |     |        v          |
9ae3a8
  0x0e0000000 +-------------------+.....+-------------------+ 0x0e0000000
9ae3a8
              |         ^         |.    |XXXXXXXXXXXXXXXXXXX|
9ae3a8
              | above_4g_mem_size | .   |XXXX PCI hole XXXXX|
9ae3a8
              |         v         |  .  |XXXX          XXXXX|
9ae3a8
     ram_size +-------------------+   . |XXXX  512 MB  XXXXX|
9ae3a8
                                   .   .|XXXXXXXXXXXXXXXXXXX|
9ae3a8
                                    .   +-------------------+ 0x100000000
9ae3a8
                                     .  |         ^         |
9ae3a8
                                      . | above_4g_mem_size |
9ae3a8
                                       .|         v         |
9ae3a8
                                        +-------------------+ ram_size
9ae3a8
                                                              + 512 MB
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 56c4bfb3f07f3107894c00281276aea4f5e8834d)
9ae3a8
9ae3a8
Conflicts:
9ae3a8
9ae3a8
	memory_mapping.c
9ae3a8
	stubs/dump.c
9ae3a8
	target-s390x/arch_dump.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 9b4f38e1 ("s390: Implement dump-guest-memory support for
9ae3a8
  target s390x") -- we don't support the s390x target.
9ae3a8
9ae3a8
diff --git a/dump.c b/dump.c
9ae3a8
index e6b7a00..0523ad4 100644
9ae3a8
--- a/dump.c
9ae3a8
+++ b/dump.c
9ae3a8
@@ -70,7 +70,7 @@ typedef struct DumpState {
9ae3a8
     hwaddr memory_offset;
9ae3a8
     int fd;
9ae3a8
 
9ae3a8
-    RAMBlock *block;
9ae3a8
+    GuestPhysBlock *next_block;
9ae3a8
     ram_addr_t start;
9ae3a8
     bool has_filter;
9ae3a8
     int64_t begin;
9ae3a8
@@ -395,14 +395,14 @@ static int write_data(DumpState *s, void *buf, int length)
9ae3a8
 }
9ae3a8
 
9ae3a8
 /* write the memroy to vmcore. 1 page per I/O. */
9ae3a8
-static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
9ae3a8
+static int write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
9ae3a8
                         int64_t size)
9ae3a8
 {
9ae3a8
     int64_t i;
9ae3a8
     int ret;
9ae3a8
 
9ae3a8
     for (i = 0; i < size / TARGET_PAGE_SIZE; i++) {
9ae3a8
-        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
9ae3a8
+        ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
9ae3a8
                          TARGET_PAGE_SIZE);
9ae3a8
         if (ret < 0) {
9ae3a8
             return ret;
9ae3a8
@@ -410,7 +410,7 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
9ae3a8
     }
9ae3a8
 
9ae3a8
     if ((size % TARGET_PAGE_SIZE) != 0) {
9ae3a8
-        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
9ae3a8
+        ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
9ae3a8
                          size % TARGET_PAGE_SIZE);
9ae3a8
         if (ret < 0) {
9ae3a8
             return ret;
9ae3a8
@@ -427,7 +427,7 @@ static void get_offset_range(hwaddr phys_addr,
9ae3a8
                              hwaddr *p_offset,
9ae3a8
                              hwaddr *p_filesz)
9ae3a8
 {
9ae3a8
-    RAMBlock *block;
9ae3a8
+    GuestPhysBlock *block;
9ae3a8
     hwaddr offset = s->memory_offset;
9ae3a8
     int64_t size_in_block, start;
9ae3a8
 
9ae3a8
@@ -441,35 +441,34 @@ static void get_offset_range(hwaddr phys_addr,
9ae3a8
         }
9ae3a8
     }
9ae3a8
 
9ae3a8
-    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
9ae3a8
+    QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
9ae3a8
         if (s->has_filter) {
9ae3a8
-            if (block->offset >= s->begin + s->length ||
9ae3a8
-                block->offset + block->length <= s->begin) {
9ae3a8
+            if (block->target_start >= s->begin + s->length ||
9ae3a8
+                block->target_end <= s->begin) {
9ae3a8
                 /* This block is out of the range */
9ae3a8
                 continue;
9ae3a8
             }
9ae3a8
 
9ae3a8
-            if (s->begin <= block->offset) {
9ae3a8
-                start = block->offset;
9ae3a8
+            if (s->begin <= block->target_start) {
9ae3a8
+                start = block->target_start;
9ae3a8
             } else {
9ae3a8
                 start = s->begin;
9ae3a8
             }
9ae3a8
 
9ae3a8
-            size_in_block = block->length - (start - block->offset);
9ae3a8
-            if (s->begin + s->length < block->offset + block->length) {
9ae3a8
-                size_in_block -= block->offset + block->length -
9ae3a8
-                                 (s->begin + s->length);
9ae3a8
+            size_in_block = block->target_end - start;
9ae3a8
+            if (s->begin + s->length < block->target_end) {
9ae3a8
+                size_in_block -= block->target_end - (s->begin + s->length);
9ae3a8
             }
9ae3a8
         } else {
9ae3a8
-            start = block->offset;
9ae3a8
-            size_in_block = block->length;
9ae3a8
+            start = block->target_start;
9ae3a8
+            size_in_block = block->target_end - block->target_start;
9ae3a8
         }
9ae3a8
 
9ae3a8
         if (phys_addr >= start && phys_addr < start + size_in_block) {
9ae3a8
             *p_offset = phys_addr - start + offset;
9ae3a8
 
9ae3a8
             /* The offset range mapped from the vmcore file must not spill over
9ae3a8
-             * the RAMBlock, clamp it. The rest of the mapping will be
9ae3a8
+             * the GuestPhysBlock, clamp it. The rest of the mapping will be
9ae3a8
              * zero-filled in memory at load time; see
9ae3a8
              * <http: refspecs.linuxbase.org="" elf="" gabi4+="" ch5.pheader.html="">.
9ae3a8
              */
9ae3a8
@@ -617,7 +616,7 @@ static int dump_completed(DumpState *s)
9ae3a8
     return 0;
9ae3a8
 }
9ae3a8
 
9ae3a8
-static int get_next_block(DumpState *s, RAMBlock *block)
9ae3a8
+static int get_next_block(DumpState *s, GuestPhysBlock *block)
9ae3a8
 {
9ae3a8
     while (1) {
9ae3a8
         block = QTAILQ_NEXT(block, next);
9ae3a8
@@ -627,16 +626,16 @@ static int get_next_block(DumpState *s, RAMBlock *block)
9ae3a8
         }
9ae3a8
 
9ae3a8
         s->start = 0;
9ae3a8
-        s->block = block;
9ae3a8
+        s->next_block = block;
9ae3a8
         if (s->has_filter) {
9ae3a8
-            if (block->offset >= s->begin + s->length ||
9ae3a8
-                block->offset + block->length <= s->begin) {
9ae3a8
+            if (block->target_start >= s->begin + s->length ||
9ae3a8
+                block->target_end <= s->begin) {
9ae3a8
                 /* This block is out of the range */
9ae3a8
                 continue;
9ae3a8
             }
9ae3a8
 
9ae3a8
-            if (s->begin > block->offset) {
9ae3a8
-                s->start = s->begin - block->offset;
9ae3a8
+            if (s->begin > block->target_start) {
9ae3a8
+                s->start = s->begin - block->target_start;
9ae3a8
             }
9ae3a8
         }
9ae3a8
 
9ae3a8
@@ -647,18 +646,18 @@ static int get_next_block(DumpState *s, RAMBlock *block)
9ae3a8
 /* write all memory to vmcore */
9ae3a8
 static int dump_iterate(DumpState *s)
9ae3a8
 {
9ae3a8
-    RAMBlock *block;
9ae3a8
+    GuestPhysBlock *block;
9ae3a8
     int64_t size;
9ae3a8
     int ret;
9ae3a8
 
9ae3a8
     while (1) {
9ae3a8
-        block = s->block;
9ae3a8
+        block = s->next_block;
9ae3a8
 
9ae3a8
-        size = block->length;
9ae3a8
+        size = block->target_end - block->target_start;
9ae3a8
         if (s->has_filter) {
9ae3a8
             size -= s->start;
9ae3a8
-            if (s->begin + s->length < block->offset + block->length) {
9ae3a8
-                size -= block->offset + block->length - (s->begin + s->length);
9ae3a8
+            if (s->begin + s->length < block->target_end) {
9ae3a8
+                size -= block->target_end - (s->begin + s->length);
9ae3a8
             }
9ae3a8
         }
9ae3a8
         ret = write_memory(s, block, s->start, size);
9ae3a8
@@ -693,23 +692,23 @@ static int create_vmcore(DumpState *s)
9ae3a8
 
9ae3a8
 static ram_addr_t get_start_block(DumpState *s)
9ae3a8
 {
9ae3a8
-    RAMBlock *block;
9ae3a8
+    GuestPhysBlock *block;
9ae3a8
 
9ae3a8
     if (!s->has_filter) {
9ae3a8
-        s->block = QTAILQ_FIRST(&ram_list.blocks);
9ae3a8
+        s->next_block = QTAILQ_FIRST(&s->guest_phys_blocks.head);
9ae3a8
         return 0;
9ae3a8
     }
9ae3a8
 
9ae3a8
-    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
9ae3a8
-        if (block->offset >= s->begin + s->length ||
9ae3a8
-            block->offset + block->length <= s->begin) {
9ae3a8
+    QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
9ae3a8
+        if (block->target_start >= s->begin + s->length ||
9ae3a8
+            block->target_end <= s->begin) {
9ae3a8
             /* This block is out of the range */
9ae3a8
             continue;
9ae3a8
         }
9ae3a8
 
9ae3a8
-        s->block = block;
9ae3a8
-        if (s->begin > block->offset) {
9ae3a8
-            s->start = s->begin - block->offset;
9ae3a8
+        s->next_block = block;
9ae3a8
+        if (s->begin > block->target_start) {
9ae3a8
+            s->start = s->begin - block->target_start;
9ae3a8
         } else {
9ae3a8
             s->start = 0;
9ae3a8
         }
9ae3a8
@@ -762,7 +761,7 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
9ae3a8
      * If the target architecture is not supported, cpu_get_dump_info() will
9ae3a8
      * return -1.
9ae3a8
      */
9ae3a8
-    ret = cpu_get_dump_info(&s->dump_info);
9ae3a8
+    ret = cpu_get_dump_info(&s->dump_info, &s->guest_phys_blocks);
9ae3a8
     if (ret < 0) {
9ae3a8
         error_set(errp, QERR_UNSUPPORTED);
9ae3a8
         goto cleanup;
9ae3a8
@@ -778,13 +777,13 @@ static int dump_init(DumpState *s, int fd, bool paging, bool has_filter,
9ae3a8
     /* get memory mapping */
9ae3a8
     memory_mapping_list_init(&s->list);
9ae3a8
     if (paging) {
9ae3a8
-        qemu_get_guest_memory_mapping(&s->list, &err);
9ae3a8
+        qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err);
9ae3a8
         if (err != NULL) {
9ae3a8
             error_propagate(errp, err);
9ae3a8
             goto cleanup;
9ae3a8
         }
9ae3a8
     } else {
9ae3a8
-        qemu_get_guest_simple_memory_mapping(&s->list);
9ae3a8
+        qemu_get_guest_simple_memory_mapping(&s->list, &s->guest_phys_blocks);
9ae3a8
     }
9ae3a8
 
9ae3a8
     if (s->has_filter) {
9ae3a8
diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h
9ae3a8
index b8c770f..19fafb2 100644
9ae3a8
--- a/include/sysemu/dump.h
9ae3a8
+++ b/include/sysemu/dump.h
9ae3a8
@@ -20,7 +20,9 @@ typedef struct ArchDumpInfo {
9ae3a8
     int d_class;    /* ELFCLASS32 or ELFCLASS64 */
9ae3a8
 } ArchDumpInfo;
9ae3a8
 
9ae3a8
-int cpu_get_dump_info(ArchDumpInfo *info);
9ae3a8
+struct GuestPhysBlockList; /* memory_mapping.h */
9ae3a8
+int cpu_get_dump_info(ArchDumpInfo *info,
9ae3a8
+                      const struct GuestPhysBlockList *guest_phys_blocks);
9ae3a8
 ssize_t cpu_get_note_size(int class, int machine, int nr_cpus);
9ae3a8
 
9ae3a8
 #endif
9ae3a8
diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h
9ae3a8
index b2d7d85..a75d59a 100644
9ae3a8
--- a/include/sysemu/memory_mapping.h
9ae3a8
+++ b/include/sysemu/memory_mapping.h
9ae3a8
@@ -68,10 +68,13 @@ 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
+void qemu_get_guest_memory_mapping(MemoryMappingList *list,
9ae3a8
+                                   const GuestPhysBlockList *guest_phys_blocks,
9ae3a8
+                                   Error **errp);
9ae3a8
 
9ae3a8
 /* get guest's memory mapping without do paging(virtual address is 0). */
9ae3a8
-void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list);
9ae3a8
+void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list,
9ae3a8
+                                  const GuestPhysBlockList *guest_phys_blocks);
9ae3a8
 
9ae3a8
 void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
9ae3a8
                            int64_t length);
9ae3a8
diff --git a/memory_mapping.c b/memory_mapping.c
9ae3a8
index 411aba6..65082d8 100644
9ae3a8
--- a/memory_mapping.c
9ae3a8
+++ b/memory_mapping.c
9ae3a8
@@ -279,10 +279,12 @@ static CPUArchState *find_paging_enabled_cpu(CPUArchState *start_cpu)
9ae3a8
     return NULL;
9ae3a8
 }
9ae3a8
 
9ae3a8
-void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp)
9ae3a8
+void qemu_get_guest_memory_mapping(MemoryMappingList *list,
9ae3a8
+                                   const GuestPhysBlockList *guest_phys_blocks,
9ae3a8
+                                   Error **errp)
9ae3a8
 {
9ae3a8
     CPUArchState *env, *first_paging_enabled_cpu;
9ae3a8
-    RAMBlock *block;
9ae3a8
+    GuestPhysBlock *block;
9ae3a8
     ram_addr_t offset, length;
9ae3a8
 
9ae3a8
     first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu);
9ae3a8
@@ -302,19 +304,21 @@ void qemu_get_guest_memory_mapping(MemoryMappingList *list, Error **errp)
9ae3a8
      * If the guest doesn't use paging, the virtual address is equal to physical
9ae3a8
      * address.
9ae3a8
      */
9ae3a8
-    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
9ae3a8
-        offset = block->offset;
9ae3a8
-        length = block->length;
9ae3a8
+    QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
9ae3a8
+        offset = block->target_start;
9ae3a8
+        length = block->target_end - block->target_start;
9ae3a8
         create_new_memory_mapping(list, offset, offset, length);
9ae3a8
     }
9ae3a8
 }
9ae3a8
 
9ae3a8
-void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list)
9ae3a8
+void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list,
9ae3a8
+                                   const GuestPhysBlockList *guest_phys_blocks)
9ae3a8
 {
9ae3a8
-    RAMBlock *block;
9ae3a8
+    GuestPhysBlock *block;
9ae3a8
 
9ae3a8
-    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
9ae3a8
-        create_new_memory_mapping(list, block->offset, 0, block->length);
9ae3a8
+    QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
9ae3a8
+        create_new_memory_mapping(list, block->target_start, 0,
9ae3a8
+                                  block->target_end - block->target_start);
9ae3a8
     }
9ae3a8
 }
9ae3a8
 
9ae3a8
diff --git a/stubs/dump.c b/stubs/dump.c
9ae3a8
index b3f42cb..5749e2c 100644
9ae3a8
--- a/stubs/dump.c
9ae3a8
+++ b/stubs/dump.c
9ae3a8
@@ -24,7 +24,8 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
9ae3a8
     error_set(errp, QERR_UNSUPPORTED);
9ae3a8
 }
9ae3a8
 
9ae3a8
-int cpu_get_dump_info(ArchDumpInfo *info)
9ae3a8
+int cpu_get_dump_info(ArchDumpInfo *info,
9ae3a8
+                      const struct GuestPhysBlockList *guest_phys_blocks)
9ae3a8
 {
9ae3a8
     return -1;
9ae3a8
 }
9ae3a8
diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c
9ae3a8
index 83898cd..a99ef8c 100644
9ae3a8
--- a/target-i386/arch_dump.c
9ae3a8
+++ b/target-i386/arch_dump.c
9ae3a8
@@ -15,6 +15,7 @@
9ae3a8
 #include "exec/cpu-all.h"
9ae3a8
 #include "sysemu/dump.h"
9ae3a8
 #include "elf.h"
9ae3a8
+#include "sysemu/memory_mapping.h"
9ae3a8
 
9ae3a8
 #ifdef TARGET_X86_64
9ae3a8
 typedef struct {
9ae3a8
@@ -388,10 +389,11 @@ int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cs,
9ae3a8
     return cpu_write_qemu_note(f, &cpu->env, opaque, 0);
9ae3a8
 }
9ae3a8
 
9ae3a8
-int cpu_get_dump_info(ArchDumpInfo *info)
9ae3a8
+int cpu_get_dump_info(ArchDumpInfo *info,
9ae3a8
+                      const GuestPhysBlockList *guest_phys_blocks)
9ae3a8
 {
9ae3a8
     bool lma = false;
9ae3a8
-    RAMBlock *block;
9ae3a8
+    GuestPhysBlock *block;
9ae3a8
 
9ae3a8
 #ifdef TARGET_X86_64
9ae3a8
     lma = !!(first_cpu->hflags & HF_LMA_MASK);
9ae3a8
@@ -409,8 +411,8 @@ int cpu_get_dump_info(ArchDumpInfo *info)
9ae3a8
     } else {
9ae3a8
         info->d_class = ELFCLASS32;
9ae3a8
 
9ae3a8
-        QTAILQ_FOREACH(block, &ram_list.blocks, next) {
9ae3a8
-            if (block->offset + block->length > UINT_MAX) {
9ae3a8
+        QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
9ae3a8
+            if (block->target_end > UINT_MAX) {
9ae3a8
                 /* The memory size is greater than 4G */
9ae3a8
                 info->d_class = ELFCLASS64;
9ae3a8
                 break;