All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
@ 2012-03-01  2:35 Wen Congyang
  2012-03-01  2:39 ` [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list Wen Congyang
                   ` (14 more replies)
  0 siblings, 15 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:35 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

Hi, all

'virsh dump' can not work when host pci device is used by guest. We have
discussed this issue here:
http://lists.nongnu.org/archive/html/qemu-devel/2011-10/msg00736.html

The last version is here:
http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.html

We have determined to introduce a new command dump to dump memory. The core
file's format can be elf.

Note:
1. The guest should be x86 or x86_64. The other arch is not supported now.
2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.
3. If the OS is in the second kernel, gdb may not work well, and crash can
   work by specifying '--machdep phys_addr=xxx' in the command line. The
   reason is that the second kernel will update the page table, and we can
   not get the page table for the first kernel.
4. The cpu's state is stored in QEMU note. You neet to modify crash to use
   it to calculate phys_base.
5. If the guest OS is 32 bit and the memory size is larger than 4G, the vmcore
   is elf64 format. You should use the gdb which is built with --enable-64-bit-bfd.
6. This patchset is based on the upstream tree, and apply one patch that is still
   in Luiz Capitulino's tree, because I use the API qemu_get_fd() in this patchset.

Changes from v6 to v7:
1. addressed Jan's comments
2. fix some bugs
3. store cpu's state into the vmcore

Changes from v5 to v6:
1. allow user to dump a fraction of the memory
2. fix some bugs

Changes from v4 to v5:
1. convert the new command dump to QAPI 

Changes from v3 to v4:
1. support it to run asynchronously
2. add API to cancel dumping and query dumping progress
3. add API to control dumping speed
4. auto cancel dumping when the user resumes vm, and the status is failed.

Changes from v2 to v3:
1. address Jan Kiszka's comment

Changes from v1 to v2:
1. fix virt addr in the vmcore.

Wen Congyang (14):
  Add API to create memory mapping list
  Add API to check whether a physical address is I/O address
  target-i386: implement cpu_get_memory_mapping()
  Add API to get memory mapping
  target-i386: Add API to write elf notes to core file
  target-i386: Add API to write cpu status to core file
  target-i386: add API to get dump info
  make gdb_id() generally avialable
  introduce a new monitor command 'dump' to dump guest's memory
  support to cancel the current dumping
  support to query dumping status
  run dump at the background
  support detached dump
  allow user to dump a fraction of the memory

 Makefile.target                   |    3 +
 configure                         |    8 +
 cpu-all.h                         |   60 +++
 cpu-common.h                      |    2 +
 dump.c                            |  904 +++++++++++++++++++++++++++++++++++++
 dump.h                            |   23 +
 exec.c                            |   11 +
 gdbstub.c                         |    9 -
 gdbstub.h                         |    9 +
 hmp-commands.hx                   |   43 ++
 hmp.c                             |   87 ++++
 hmp.h                             |    3 +
 memory_mapping.c                  |  232 ++++++++++
 memory_mapping.h                  |   54 +++
 monitor.c                         |    7 +
 qapi-schema.json                  |   57 +++
 qmp-commands.hx                   |  109 +++++
 target-i386/arch_dump.c           |  437 ++++++++++++++++++
 target-i386/arch_memory_mapping.c |  256 +++++++++++
 vl.c                              |    5 +-
 20 files changed, 2308 insertions(+), 11 deletions(-)
 create mode 100644 dump.c
 create mode 100644 dump.h
 create mode 100644 memory_mapping.c
 create mode 100644 memory_mapping.h
 create mode 100644 target-i386/arch_dump.c
 create mode 100644 target-i386/arch_memory_mapping.c

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
@ 2012-03-01  2:39 ` Wen Congyang
  2012-03-01  8:33   ` HATAYAMA Daisuke
  2012-03-01  2:40 ` [Qemu-devel] [RFC][PATCH 02/14 v7] Add API to check whether a physical address is I/O address Wen Congyang
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:39 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

The memory mapping list stores virtual address and physical address mapping.
The folloing patch will use this information to create PT_LOAD in the vmcore.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>

---
 Makefile.target  |    1 +
 memory_mapping.c |  134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 memory_mapping.h |   44 ++++++++++++++++++
 3 files changed, 179 insertions(+), 0 deletions(-)
 create mode 100644 memory_mapping.c
 create mode 100644 memory_mapping.h

diff --git a/Makefile.target b/Makefile.target
index 68a5641..9227e4e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -208,6 +208,7 @@ obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-$(CONFIG_VGA) += vga.o
 obj-y += memory.o savevm.o
+obj-y += memory_mapping.o
 LIBS+=-lz
 
 obj-i386-$(CONFIG_KVM) += hyperv.o
diff --git a/memory_mapping.c b/memory_mapping.c
new file mode 100644
index 0000000..84fb2c8
--- /dev/null
+++ b/memory_mapping.c
@@ -0,0 +1,134 @@
+/*
+ * QEMU memory mapping
+ *
+ * Copyright Fujitsu, Corp. 2011, 2012
+ *
+ * Authors:
+ *     Wen Congyang <wency@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "cpu.h"
+#include "cpu-all.h"
+#include "memory_mapping.h"
+
+static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
+                                                   MemoryMapping *mapping)
+{
+    MemoryMapping *p;
+
+    QTAILQ_FOREACH(p, &list->head, next) {
+        if (p->phys_addr >= mapping->phys_addr) {
+            QTAILQ_INSERT_BEFORE(p, mapping, next);
+            return;
+        }
+    }
+    QTAILQ_INSERT_TAIL(&list->head, mapping, next);
+}
+
+static void create_new_memory_mapping(MemoryMappingList *list,
+                                      target_phys_addr_t phys_addr,
+                                      target_phys_addr_t virt_addr,
+                                      ram_addr_t length)
+{
+    MemoryMapping *memory_mapping;
+
+    memory_mapping = g_malloc(sizeof(MemoryMapping));
+    memory_mapping->phys_addr = phys_addr;
+    memory_mapping->virt_addr = virt_addr;
+    memory_mapping->length = length;
+    list->last_mapping = memory_mapping;
+    list->num++;
+    memory_mapping_list_add_mapping_sorted(list, memory_mapping);
+}
+
+void memory_mapping_list_add_sorted(MemoryMappingList *list,
+                                    target_phys_addr_t phys_addr,
+                                    target_phys_addr_t virt_addr,
+                                    ram_addr_t length)
+{
+    MemoryMapping *memory_mapping, *last_mapping;
+
+    if (QTAILQ_EMPTY(&list->head)) {
+        create_new_memory_mapping(list, phys_addr, virt_addr, length);
+        return;
+    }
+
+    last_mapping = list->last_mapping;
+    if (last_mapping) {
+        if ((phys_addr == (last_mapping->phys_addr + last_mapping->length)) &&
+            (virt_addr == (last_mapping->virt_addr + last_mapping->length))) {
+            last_mapping->length += length;
+            return;
+        }
+    }
+
+    QTAILQ_FOREACH(memory_mapping, &list->head, next) {
+        last_mapping = memory_mapping;
+        if ((phys_addr == (last_mapping->phys_addr + last_mapping->length)) &&
+            (virt_addr == (last_mapping->virt_addr + last_mapping->length))) {
+            last_mapping->length += length;
+            list->last_mapping = last_mapping;
+            return;
+        }
+
+        if (phys_addr + length < last_mapping->phys_addr) {
+            /* create a new region before last_mapping */
+            break;
+        }
+
+        if (phys_addr >= (last_mapping->phys_addr + last_mapping->length)) {
+            /* last_mapping does not contain this region */
+            continue;
+        }
+
+        if ((virt_addr - last_mapping->virt_addr) !=
+            (phys_addr - last_mapping->phys_addr)) {
+            /*
+             * last_mapping contains this region, but we cannot merge this
+             * region into last_mapping. Try the next memory mapping.
+             */
+            continue;
+        }
+
+        /* merge this region into last_mapping */
+        if (virt_addr < last_mapping->virt_addr) {
+            last_mapping->length += last_mapping->virt_addr - virt_addr;
+            last_mapping->virt_addr = virt_addr;
+        }
+
+        if ((virt_addr + length) >
+            (last_mapping->virt_addr + last_mapping->length)) {
+            last_mapping->length = virt_addr + length - last_mapping->virt_addr;
+        }
+
+        list->last_mapping = last_mapping;
+        return;
+    }
+
+    /* this region can not be merged into any existed memory mapping. */
+    create_new_memory_mapping(list, phys_addr, virt_addr, length);
+}
+
+void memory_mapping_list_free(MemoryMappingList *list)
+{
+    MemoryMapping *p, *q;
+
+    QTAILQ_FOREACH_SAFE(p, &list->head, next, q) {
+        QTAILQ_REMOVE(&list->head, p, next);
+        g_free(p);
+    }
+
+    list->num = 0;
+    list->last_mapping = NULL;
+}
+
+void memory_mapping_list_init(MemoryMappingList *list)
+{
+    list->num = 0;
+    list->last_mapping = NULL;
+    QTAILQ_INIT(&list->head);
+}
diff --git a/memory_mapping.h b/memory_mapping.h
new file mode 100644
index 0000000..633fcb9
--- /dev/null
+++ b/memory_mapping.h
@@ -0,0 +1,44 @@
+/*
+ * QEMU memory mapping
+ *
+ * Copyright Fujitsu, Corp. 2011, 2012
+ *
+ * Authors:
+ *     Wen Congyang <wency@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef MEMORY_MAPPING_H
+#define MEMORY_MAPPING_H
+
+#include "qemu-queue.h"
+
+typedef struct MemoryMapping {
+    target_phys_addr_t phys_addr;
+    target_ulong virt_addr;
+    ram_addr_t length;
+    QTAILQ_ENTRY(MemoryMapping) next;
+} MemoryMapping;
+
+typedef struct MemoryMappingList {
+    unsigned int num;
+    MemoryMapping *last_mapping;
+    QTAILQ_HEAD(, MemoryMapping) head;
+} MemoryMappingList;
+
+/*
+ * add or merge the memory region into the memory mapping's list. The list is
+ * sorted by phys_addr.
+ */
+void memory_mapping_list_add_sorted(MemoryMappingList *list,
+                                    target_phys_addr_t phys_addr,
+                                    target_phys_addr_t virt_addr,
+                                    ram_addr_t length);
+
+void memory_mapping_list_free(MemoryMappingList *list);
+void memory_mapping_list_init(MemoryMappingList *list);
+
+#endif
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 02/14 v7] Add API to check whether a physical address is I/O address
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
  2012-03-01  2:39 ` [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list Wen Congyang
@ 2012-03-01  2:40 ` Wen Congyang
  2012-03-01  2:41 ` [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping() Wen Congyang
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:40 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

This API will be used in the following patch.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 cpu-common.h |    2 ++
 exec.c       |   11 +++++++++++
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/cpu-common.h b/cpu-common.h
index a40c57d..fde3e5d 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -71,6 +71,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
 void *cpu_register_map_client(void *opaque, void (*callback)(void *opaque));
 void cpu_unregister_map_client(void *cookie);
 
+bool cpu_physical_memory_is_io(target_phys_addr_t phys_addr);
+
 /* Coalesced MMIO regions are areas where write operations can be reordered.
  * This usually implies that write operations are side-effect free.  This allows
  * batching which can make a major impact on performance when using
diff --git a/exec.c b/exec.c
index b81677a..2114dd5 100644
--- a/exec.c
+++ b/exec.c
@@ -4435,3 +4435,14 @@ bool virtio_is_big_endian(void)
 #undef env
 
 #endif
+
+bool cpu_physical_memory_is_io(target_phys_addr_t phys_addr)
+{
+    ram_addr_t pd;
+    PhysPageDesc p;
+
+    p = phys_page_find(phys_addr >> TARGET_PAGE_BITS);
+    pd = p.phys_offset;
+
+    return !is_ram_rom_romd(pd);
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
  2012-03-01  2:39 ` [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list Wen Congyang
  2012-03-01  2:40 ` [Qemu-devel] [RFC][PATCH 02/14 v7] Add API to check whether a physical address is I/O address Wen Congyang
@ 2012-03-01  2:41 ` Wen Congyang
  2012-03-01  6:13   ` HATAYAMA Daisuke
  2012-03-01  2:43 ` [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping Wen Congyang
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:41 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

Walk cpu's page table and collect all virtual address and physical address mapping.
Then, add these mapping into memory mapping list.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 Makefile.target                   |    1 +
 configure                         |    4 +
 cpu-all.h                         |   10 ++
 target-i386/arch_memory_mapping.c |  256 +++++++++++++++++++++++++++++++++++++
 4 files changed, 271 insertions(+), 0 deletions(-)
 create mode 100644 target-i386/arch_memory_mapping.c

diff --git a/Makefile.target b/Makefile.target
index 9227e4e..a87e678 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -84,6 +84,7 @@ libobj-y += op_helper.o helper.o
 ifeq ($(TARGET_BASE_ARCH), i386)
 libobj-y += cpuid.o
 endif
+libobj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += arch_memory_mapping.o
 libobj-$(TARGET_SPARC64) += vis_helper.o
 libobj-$(CONFIG_NEED_MMU) += mmu.o
 libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
diff --git a/configure b/configure
index f9d5330..ddc54f5 100755
--- a/configure
+++ b/configure
@@ -3630,6 +3630,10 @@ case "$target_arch2" in
       fi
     fi
 esac
+case "$target_arch2" in
+  i386|x86_64)
+    echo "CONFIG_HAVE_GET_MEMORY_MAPPING=y" >> $config_target_mak
+esac
 if test "$target_arch2" = "ppc64" -a "$fdt" = "yes"; then
   echo "CONFIG_PSERIES=y" >> $config_target_mak
 fi
diff --git a/cpu-all.h b/cpu-all.h
index e2c3c49..cb72680 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -22,6 +22,7 @@
 #include "qemu-common.h"
 #include "qemu-tls.h"
 #include "cpu-common.h"
+#include "memory_mapping.h"
 
 /* some important defines:
  *
@@ -523,4 +524,13 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf);
 int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
                         uint8_t *buf, int len, int is_write);
 
+#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
+int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env);
+#else
+static inline int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
+{
+    return -1;
+}
+#endif
+
 #endif /* CPU_ALL_H */
diff --git a/target-i386/arch_memory_mapping.c b/target-i386/arch_memory_mapping.c
new file mode 100644
index 0000000..8dcc010
--- /dev/null
+++ b/target-i386/arch_memory_mapping.c
@@ -0,0 +1,256 @@
+/*
+ * i386 memory mapping
+ *
+ * Copyright Fujitsu, Corp. 2011
+ *
+ * Authors:
+ *     Wen Congyang <wency@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "cpu.h"
+#include "cpu-all.h"
+
+/* PAE Paging or IA-32e Paging */
+static void walk_pte(MemoryMappingList *list, target_phys_addr_t pte_start_addr,
+                     int32_t a20_mask, target_ulong start_line_addr)
+{
+    target_phys_addr_t pte_addr, start_paddr;
+    uint64_t pte;
+    target_ulong start_vaddr;
+    int i;
+
+    for (i = 0; i < 512; i++) {
+        pte_addr = (pte_start_addr + i * 8) & a20_mask;
+        pte = ldq_phys(pte_addr);
+        if (!(pte & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        start_paddr = (pte & ~0xfff) & ~(0x1ULL << 63);
+        if (cpu_physical_memory_is_io(start_paddr)) {
+            /* I/O region */
+            continue;
+        }
+
+        start_vaddr = start_line_addr | ((i & 0x1fff) << 12);
+        memory_mapping_list_add_sorted(list, start_paddr, start_vaddr, 1 << 12);
+    }
+}
+
+/* 32-bit Paging */
+static void walk_pte2(MemoryMappingList *list,
+                      target_phys_addr_t pte_start_addr, int32_t a20_mask,
+                      target_ulong start_line_addr)
+{
+    target_phys_addr_t pte_addr, start_paddr;
+    uint32_t pte;
+    target_ulong start_vaddr;
+    int i;
+
+    for (i = 0; i < 1024; i++) {
+        pte_addr = (pte_start_addr + i * 4) & a20_mask;
+        pte = ldl_phys(pte_addr);
+        if (!(pte & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        start_paddr = pte & ~0xfff;
+        if (cpu_physical_memory_is_io(start_paddr)) {
+            /* I/O region */
+            continue;
+        }
+
+        start_vaddr = start_line_addr | ((i & 0x3ff) << 12);
+        memory_mapping_list_add_sorted(list, start_paddr, start_vaddr, 1 << 12);
+    }
+}
+
+/* PAE Paging or IA-32e Paging */
+static void walk_pde(MemoryMappingList *list, target_phys_addr_t pde_start_addr,
+                     int32_t a20_mask, target_ulong start_line_addr)
+{
+    target_phys_addr_t pde_addr, pte_start_addr, start_paddr;
+    uint64_t pde;
+    target_ulong line_addr, start_vaddr;
+    int i;
+
+    for (i = 0; i < 512; i++) {
+        pde_addr = (pde_start_addr + i * 8) & a20_mask;
+        pde = ldq_phys(pde_addr);
+        if (!(pde & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = start_line_addr | ((i & 0x1ff) << 21);
+        if (pde & PG_PSE_MASK) {
+            /* 2 MB page */
+            start_paddr = (pde & ~0x1fffff) & ~(0x1ULL << 63);
+            if (cpu_physical_memory_is_io(start_paddr)) {
+                /* I/O region */
+                continue;
+            }
+            start_vaddr = line_addr;
+            memory_mapping_list_add_sorted(list, start_paddr, start_vaddr, 1 << 21);
+            continue;
+        }
+
+        pte_start_addr = (pde & ~0xfff) & a20_mask;
+        walk_pte(list, pte_start_addr, a20_mask, line_addr);
+    }
+}
+
+/* 32-bit Paging */
+static void walk_pde2(MemoryMappingList *list,
+                      target_phys_addr_t pde_start_addr, int32_t a20_mask,
+                      bool pse)
+{
+    target_phys_addr_t pde_addr, pte_start_addr, start_paddr;
+    uint32_t pde;
+    target_ulong line_addr, start_vaddr;
+    int i;
+
+    for (i = 0; i < 1024; i++) {
+        pde_addr = (pde_start_addr + i * 4) & a20_mask;
+        pde = ldl_phys(pde_addr);
+        if (!(pde & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = (((unsigned int)i & 0x3ff) << 22);
+        if ((pde & PG_PSE_MASK) && pse) {
+            /* 4 MB page */
+            start_paddr = (pde & ~0x3fffff) | ((pde & 0x1fe000) << 19);
+            if (cpu_physical_memory_is_io(start_paddr)) {
+                /* I/O region */
+                continue;
+            }
+            start_vaddr = line_addr;
+            memory_mapping_list_add_sorted(list, start_paddr, start_vaddr, 1 << 22);
+            continue;
+        }
+
+        pte_start_addr = (pde & ~0xfff) & a20_mask;
+        walk_pte2(list, pte_start_addr, a20_mask, line_addr);
+    }
+}
+
+/* PAE Paging */
+static void walk_pdpe2(MemoryMappingList *list,
+                       target_phys_addr_t pdpe_start_addr, int32_t a20_mask)
+{
+    target_phys_addr_t pdpe_addr, pde_start_addr;
+    uint64_t pdpe;
+    target_ulong line_addr;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        pdpe_addr = (pdpe_start_addr + i * 8) & a20_mask;
+        pdpe = ldq_phys(pdpe_addr);
+        if (!(pdpe & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = (((unsigned int)i & 0x3) << 30);
+        pde_start_addr = (pdpe & ~0xfff) & a20_mask;
+        walk_pde(list, pde_start_addr, a20_mask, line_addr);
+    }
+}
+
+#ifdef TARGET_X86_64
+/* IA-32e Paging */
+static void walk_pdpe(MemoryMappingList *list,
+                      target_phys_addr_t pdpe_start_addr, int32_t a20_mask,
+                      target_ulong start_line_addr)
+{
+    target_phys_addr_t pdpe_addr, pde_start_addr, start_paddr;
+    uint64_t pdpe;
+    target_ulong line_addr, start_vaddr;
+    int i;
+
+    for (i = 0; i < 512; i++) {
+        pdpe_addr = (pdpe_start_addr + i * 8) & a20_mask;
+        pdpe = ldq_phys(pdpe_addr);
+        if (!(pdpe & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = start_line_addr | ((i & 0x1ffULL) << 30);
+        if (pdpe & PG_PSE_MASK) {
+            /* 1 GB page */
+            start_paddr = (pdpe & ~0x3fffffff) & ~(0x1ULL << 63);
+            if (cpu_physical_memory_is_io(start_paddr)) {
+                /* I/O region */
+                continue;
+            }
+            start_vaddr = line_addr;
+            memory_mapping_list_add_sorted(list, start_paddr, start_vaddr, 1 << 30);
+            continue;
+        }
+
+        pde_start_addr = (pdpe & ~0xfff) & a20_mask;
+        walk_pde(list, pde_start_addr, a20_mask, line_addr);
+    }
+}
+
+/* IA-32e Paging */
+static void walk_pml4e(MemoryMappingList *list,
+                       target_phys_addr_t pml4e_start_addr, int32_t a20_mask)
+{
+    target_phys_addr_t pml4e_addr, pdpe_start_addr;
+    uint64_t pml4e;
+    target_ulong line_addr;
+    int i;
+
+    for (i = 0; i < 512; i++) {
+        pml4e_addr = (pml4e_start_addr + i * 8) & a20_mask;
+        pml4e = ldq_phys(pml4e_addr);
+        if (!(pml4e & PG_PRESENT_MASK)) {
+            /* not present */
+            continue;
+        }
+
+        line_addr = ((i & 0x1ffULL) << 39) | (0xffffULL << 48);
+        pdpe_start_addr = (pml4e & ~0xfff) & a20_mask;
+        walk_pdpe(list, pdpe_start_addr, a20_mask, line_addr);
+    }
+}
+#endif
+
+int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
+{
+    if (env->cr[4] & CR4_PAE_MASK) {
+#ifdef TARGET_X86_64
+        if (env->hflags & HF_LMA_MASK) {
+            target_phys_addr_t pml4e_addr;
+
+            pml4e_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
+            walk_pml4e(list, pml4e_addr, env->a20_mask);
+        } else
+#endif
+        {
+            target_phys_addr_t pdpe_addr;
+
+            pdpe_addr = (env->cr[3] & ~0x1f) & env->a20_mask;
+            walk_pdpe2(list, pdpe_addr, env->a20_mask);
+        }
+    } else {
+        target_phys_addr_t pde_addr;
+        bool pse;
+
+        pde_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
+        pse = !!(env->cr[4] & CR4_PSE_MASK);
+        walk_pde2(list, pde_addr, env->a20_mask, pse);
+    }
+
+    return 0;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (2 preceding siblings ...)
  2012-03-01  2:41 ` [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping() Wen Congyang
@ 2012-03-01  2:43 ` Wen Congyang
  2012-03-01  6:01   ` HATAYAMA Daisuke
  2012-03-01  2:45 ` [Qemu-devel] [RFC][PATCH 05/14 v7] target-i386: Add API to write elf notes to core file Wen Congyang
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:43 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

Add API to get all virtual address and physical address mapping.
If there is no virtual address for some physical address, the virtual
address is 0.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 memory_mapping.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 memory_mapping.h |    8 ++++++
 2 files changed, 79 insertions(+), 0 deletions(-)

diff --git a/memory_mapping.c b/memory_mapping.c
index 84fb2c8..3743805 100644
--- a/memory_mapping.c
+++ b/memory_mapping.c
@@ -132,3 +132,74 @@ void memory_mapping_list_init(MemoryMappingList *list)
     list->last_mapping = NULL;
     QTAILQ_INIT(&list->head);
 }
+
+int qemu_get_guest_memory_mapping(MemoryMappingList *list)
+{
+    CPUState *env;
+    MemoryMapping *memory_mapping;
+    RAMBlock *block;
+    ram_addr_t offset, length;
+    int ret;
+
+#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        ret = cpu_get_memory_mapping(list, env);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+#else
+    return -2;
+#endif
+
+    /* some memory may be not mapped, add them into memory mapping's list */
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        offset = block->offset;
+        length = block->length;
+
+        QTAILQ_FOREACH(memory_mapping, &list->head, next) {
+            if (memory_mapping->phys_addr >= (offset + length)) {
+                /*
+                 * memory_mapping's list does not conatin the region
+                 * [offset, offset+length)
+                 */
+                create_new_memory_mapping(list, offset, 0, length);
+                length = 0;
+                break;
+            }
+
+            if ((memory_mapping->phys_addr + memory_mapping->length) <=
+                offset) {
+                continue;
+            }
+
+            if (memory_mapping->phys_addr > offset) {
+                /*
+                 * memory_mapping's list does not conatin the region
+                 * [offset, memory_mapping->phys_addr)
+                 */
+                create_new_memory_mapping(list, offset, 0,
+                                          memory_mapping->phys_addr - offset);
+            }
+
+            if ((offset + length) <=
+                (memory_mapping->phys_addr + memory_mapping->length)) {
+                length = 0;
+                break;
+            }
+            length -= memory_mapping->phys_addr + memory_mapping->length -
+                      offset;
+            offset = memory_mapping->phys_addr + memory_mapping->length;
+        }
+
+        if (length > 0) {
+            /*
+             * memory_mapping's list does not conatin the region
+             * [offset, memory_mapping->phys_addr)
+             */
+            create_new_memory_mapping(list, offset, 0, length);
+        }
+    }
+
+    return 0;
+}
diff --git a/memory_mapping.h b/memory_mapping.h
index 633fcb9..5760d1d 100644
--- a/memory_mapping.h
+++ b/memory_mapping.h
@@ -41,4 +41,12 @@ void memory_mapping_list_add_sorted(MemoryMappingList *list,
 void memory_mapping_list_free(MemoryMappingList *list);
 void memory_mapping_list_init(MemoryMappingList *list);
 
+/*
+ * Return value:
+ *    0: success
+ *   -1: failed
+ *   -2: unsupported
+ */
+int qemu_get_guest_memory_mapping(MemoryMappingList *list);
+
 #endif
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 05/14 v7] target-i386: Add API to write elf notes to core file
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (3 preceding siblings ...)
  2012-03-01  2:43 ` [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping Wen Congyang
@ 2012-03-01  2:45 ` Wen Congyang
  2012-03-01  2:48 ` [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status " Wen Congyang
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:45 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

The core file contains register's value. These APIs write registers to
core file, and them will be called in the following patch.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 Makefile.target         |    1 +
 configure               |    4 +
 cpu-all.h               |   23 +++++
 target-i386/arch_dump.c |  249 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 277 insertions(+), 0 deletions(-)
 create mode 100644 target-i386/arch_dump.c

diff --git a/Makefile.target b/Makefile.target
index a87e678..cfd3113 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -210,6 +210,7 @@ obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-$(CONFIG_VGA) += vga.o
 obj-y += memory.o savevm.o
 obj-y += memory_mapping.o
+obj-$(CONFIG_HAVE_CORE_DUMP) += arch_dump.o
 LIBS+=-lz
 
 obj-i386-$(CONFIG_KVM) += hyperv.o
diff --git a/configure b/configure
index ddc54f5..d2f24d3 100755
--- a/configure
+++ b/configure
@@ -3649,6 +3649,10 @@ if test "$target_softmmu" = "yes" ; then
   if test "$smartcard_nss" = "yes" ; then
     echo "subdir-$target: subdir-libcacard" >> $config_host_mak
   fi
+  case "$target_arch2" in
+    i386|x86_64)
+      echo "CONFIG_HAVE_CORE_DUMP=y" >> $config_target_mak
+  esac
 fi
 if test "$target_user_only" = "yes" ; then
   echo "CONFIG_USER_ONLY=y" >> $config_target_mak
diff --git a/cpu-all.h b/cpu-all.h
index cb72680..f7c6321 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -533,4 +533,27 @@ static inline int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
 }
 #endif
 
+typedef int (*write_core_dump_function)
+    (target_phys_addr_t offset, void *buf, size_t size, void *opaque);
+#if defined(CONFIG_HAVE_CORE_DUMP)
+int cpu_write_elf64_note(write_core_dump_function f, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset, void *opaque);
+int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset, void *opaque);
+#else
+static inline int cpu_write_elf64_note(write_core_dump_function f,
+                                       CPUState *env, int cpuid,
+                                       target_phys_addr_t *offset, void *opaque)
+{
+    return -1;
+}
+
+static inline int cpu_write_elf32_note(write_core_dump_function f,
+                                       CPUState *env, int cpuid,
+                                       target_phys_addr_t *offset, void *opaque)
+{
+    return -1;
+}
+#endif
+
 #endif /* CPU_ALL_H */
diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c
new file mode 100644
index 0000000..3239c40
--- /dev/null
+++ b/target-i386/arch_dump.c
@@ -0,0 +1,249 @@
+/*
+ * i386 memory mapping
+ *
+ * Copyright Fujitsu, Corp. 2011
+ *
+ * Authors:
+ *     Wen Congyang <wency@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "cpu.h"
+#include "cpu-all.h"
+#include "elf.h"
+
+#ifdef TARGET_X86_64
+typedef struct {
+    target_ulong r15, r14, r13, r12, rbp, rbx, r11, r10;
+    target_ulong r9, r8, rax, rcx, rdx, rsi, rdi, orig_rax;
+    target_ulong rip, cs, eflags;
+    target_ulong rsp, ss;
+    target_ulong fs_base, gs_base;
+    target_ulong ds, es, fs, gs;
+} x86_64_user_regs_struct;
+
+static int x86_64_write_elf64_note(write_core_dump_function f, CPUState *env,
+                                   int id, target_phys_addr_t *offset,
+                                   void *opaque)
+{
+    x86_64_user_regs_struct regs;
+    Elf64_Nhdr *note;
+    char *buf;
+    int descsz, note_size, name_size = 5;
+    const char *name = "CORE";
+    int ret;
+
+    regs.r15 = env->regs[15];
+    regs.r14 = env->regs[14];
+    regs.r13 = env->regs[13];
+    regs.r12 = env->regs[12];
+    regs.r11 = env->regs[11];
+    regs.r10 = env->regs[10];
+    regs.r9  = env->regs[9];
+    regs.r8  = env->regs[8];
+    regs.rbp = env->regs[R_EBP];
+    regs.rsp = env->regs[R_ESP];
+    regs.rdi = env->regs[R_EDI];
+    regs.rsi = env->regs[R_ESI];
+    regs.rdx = env->regs[R_EDX];
+    regs.rcx = env->regs[R_ECX];
+    regs.rbx = env->regs[R_EBX];
+    regs.rax = env->regs[R_EAX];
+    regs.rip = env->eip;
+    regs.eflags = env->eflags;
+
+    regs.orig_rax = 0; /* FIXME */
+    regs.cs = env->segs[R_CS].selector;
+    regs.ss = env->segs[R_SS].selector;
+    regs.fs_base = env->segs[R_FS].base;
+    regs.gs_base = env->segs[R_GS].base;
+    regs.ds = env->segs[R_DS].selector;
+    regs.es = env->segs[R_ES].selector;
+    regs.fs = env->segs[R_FS].selector;
+    regs.gs = env->segs[R_GS].selector;
+
+    descsz = 336; /* sizeof(prstatus_t) is 336 on x86_64 box */
+    note_size = ((sizeof(Elf64_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+                (descsz + 3) / 4) * 4;
+    note = g_malloc(note_size);
+
+    memset(note, 0, note_size);
+    note->n_namesz = cpu_to_le32(name_size);
+    note->n_descsz = cpu_to_le32(descsz);
+    note->n_type = cpu_to_le32(NT_PRSTATUS);
+    buf = (char *)note;
+    buf += ((sizeof(Elf64_Nhdr) + 3) / 4) * 4;
+    memcpy(buf, name, name_size);
+    buf += ((name_size + 3) / 4) * 4;
+    memcpy(buf + 32, &id, 4); /* pr_pid */
+    buf += descsz - sizeof(x86_64_user_regs_struct)-sizeof(target_ulong);
+    memcpy(buf, &regs, sizeof(x86_64_user_regs_struct));
+
+    ret = f(*offset, note, note_size, opaque);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}
+#endif
+
+typedef struct {
+    uint32_t ebx, ecx, edx, esi, edi, ebp, eax;
+    unsigned short ds, __ds, es, __es;
+    unsigned short fs, __fs, gs, __gs;
+    uint32_t orig_eax, eip;
+    unsigned short cs, __cs;
+    uint32_t eflags, esp;
+    unsigned short ss, __ss;
+} x86_user_regs_struct;
+
+static int x86_write_elf64_note(write_core_dump_function f, CPUState *env,
+                                int id, target_phys_addr_t *offset,
+                                void *opaque)
+{
+    x86_user_regs_struct regs;
+    Elf64_Nhdr *note;
+    char *buf;
+    int descsz, note_size, name_size = 5;
+    const char *name = "CORE";
+    int ret;
+
+    regs.ebp = env->regs[R_EBP] & 0xffffffff;
+    regs.esp = env->regs[R_ESP] & 0xffffffff;
+    regs.edi = env->regs[R_EDI] & 0xffffffff;
+    regs.esi = env->regs[R_ESI] & 0xffffffff;
+    regs.edx = env->regs[R_EDX] & 0xffffffff;
+    regs.ecx = env->regs[R_ECX] & 0xffffffff;
+    regs.ebx = env->regs[R_EBX] & 0xffffffff;
+    regs.eax = env->regs[R_EAX] & 0xffffffff;
+    regs.eip = env->eip & 0xffffffff;
+    regs.eflags = env->eflags & 0xffffffff;
+
+    regs.cs = env->segs[R_CS].selector;
+    regs.__cs = 0;
+    regs.ss = env->segs[R_SS].selector;
+    regs.__ss = 0;
+    regs.ds = env->segs[R_DS].selector;
+    regs.__ds = 0;
+    regs.es = env->segs[R_ES].selector;
+    regs.__es = 0;
+    regs.fs = env->segs[R_FS].selector;
+    regs.__fs = 0;
+    regs.gs = env->segs[R_GS].selector;
+    regs.__gs = 0;
+
+    descsz = 144; /* sizeof(prstatus_t) is 144 on x86 box */
+    note_size = ((sizeof(Elf64_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+                (descsz + 3) / 4) * 4;
+    note = g_malloc(note_size);
+
+    memset(note, 0, note_size);
+    note->n_namesz = cpu_to_le32(name_size);
+    note->n_descsz = cpu_to_le32(descsz);
+    note->n_type = cpu_to_le32(NT_PRSTATUS);
+    buf = (char *)note;
+    buf += ((sizeof(Elf64_Nhdr) + 3) / 4) * 4;
+    memcpy(buf, name, name_size);
+    buf += ((name_size + 3) / 4) * 4;
+    memcpy(buf + 24, &id, 4); /* pr_pid */
+    buf += descsz - sizeof(x86_user_regs_struct)-4;
+    memcpy(buf, &regs, sizeof(x86_user_regs_struct));
+
+    ret = f(*offset, note, note_size, opaque);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}
+
+int cpu_write_elf64_note(write_core_dump_function f, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset, void *opaque)
+{
+    int ret;
+#ifdef TARGET_X86_64
+    bool lma = !!(first_cpu->hflags & HF_LMA_MASK);
+
+    if (lma) {
+        ret = x86_64_write_elf64_note(f, env, cpuid, offset, opaque);
+    } else {
+#endif
+        ret = x86_write_elf64_note(f, env, cpuid, offset, opaque);
+#ifdef TARGET_X86_64
+    }
+#endif
+
+    return ret;
+}
+
+int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid,
+                         target_phys_addr_t *offset, void *opaque)
+{
+    x86_user_regs_struct regs;
+    Elf32_Nhdr *note;
+    char *buf;
+    int descsz, note_size, name_size = 5;
+    const char *name = "CORE";
+    int ret;
+
+    regs.ebp = env->regs[R_EBP] & 0xffffffff;
+    regs.esp = env->regs[R_ESP] & 0xffffffff;
+    regs.edi = env->regs[R_EDI] & 0xffffffff;
+    regs.esi = env->regs[R_ESI] & 0xffffffff;
+    regs.edx = env->regs[R_EDX] & 0xffffffff;
+    regs.ecx = env->regs[R_ECX] & 0xffffffff;
+    regs.ebx = env->regs[R_EBX] & 0xffffffff;
+    regs.eax = env->regs[R_EAX] & 0xffffffff;
+    regs.eip = env->eip & 0xffffffff;
+    regs.eflags = env->eflags & 0xffffffff;
+
+    regs.cs = env->segs[R_CS].selector;
+    regs.__cs = 0;
+    regs.ss = env->segs[R_SS].selector;
+    regs.__ss = 0;
+    regs.ds = env->segs[R_DS].selector;
+    regs.__ds = 0;
+    regs.es = env->segs[R_ES].selector;
+    regs.__es = 0;
+    regs.fs = env->segs[R_FS].selector;
+    regs.__fs = 0;
+    regs.gs = env->segs[R_GS].selector;
+    regs.__gs = 0;
+
+    descsz = 144; /* sizeof(prstatus_t) is 144 on x86 box */
+    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+                (descsz + 3) / 4) * 4;
+    note = g_malloc(note_size);
+
+    memset(note, 0, note_size);
+    note->n_namesz = cpu_to_le32(name_size);
+    note->n_descsz = cpu_to_le32(descsz);
+    note->n_type = cpu_to_le32(NT_PRSTATUS);
+    buf = (char *)note;
+    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
+    memcpy(buf, name, name_size);
+    buf += ((name_size + 3) / 4) * 4;
+    memcpy(buf + 24, &cpuid, 4); /* pr_pid */
+    buf += descsz - sizeof(x86_user_regs_struct)-4;
+    memcpy(buf, &regs, sizeof(x86_user_regs_struct));
+
+    ret = f(*offset, note, note_size, opaque);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (4 preceding siblings ...)
  2012-03-01  2:45 ` [Qemu-devel] [RFC][PATCH 05/14 v7] target-i386: Add API to write elf notes to core file Wen Congyang
@ 2012-03-01  2:48 ` Wen Congyang
  2012-03-01  5:01   ` HATAYAMA Daisuke
                     ` (2 more replies)
  2012-03-01  2:49 ` [Qemu-devel] [RFC][PATCH 07/14 v7] target-i386: add API to get dump info Wen Congyang
                   ` (8 subsequent siblings)
  14 siblings, 3 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:48 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

The core file has register's value. But it does not include all register.
Store the cpu status into QEMU note, and the user can get more information
from vmcore.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 cpu-all.h               |   20 ++++++
 target-i386/arch_dump.c |  154 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 174 insertions(+), 0 deletions(-)

diff --git a/cpu-all.h b/cpu-all.h
index f7c6321..ad69269 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -540,6 +540,10 @@ int cpu_write_elf64_note(write_core_dump_function f, CPUState *env, int cpuid,
                          target_phys_addr_t *offset, void *opaque);
 int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid,
                          target_phys_addr_t *offset, void *opaque);
+int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque);
+int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque);
 #else
 static inline int cpu_write_elf64_note(write_core_dump_function f,
                                        CPUState *env, int cpuid,
@@ -554,6 +558,22 @@ static inline int cpu_write_elf32_note(write_core_dump_function f,
 {
     return -1;
 }
+
+static inline int cpu_write_elf64_qemunote(write_core_dump_function f,
+                                           CPUState *env,
+                                           target_phys_addr_t *offset,
+                                           void *opaque);
+{
+    return -1;
+}
+
+static inline int cpu_write_elf32_qemunote(write_core_dump_function f,
+                                           CPUState *env,
+                                           target_phys_addr_t *offset,
+                                           void *opaque)
+{
+    return -1;
+}
 #endif
 
 #endif /* CPU_ALL_H */
diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c
index 3239c40..560c8a3 100644
--- a/target-i386/arch_dump.c
+++ b/target-i386/arch_dump.c
@@ -247,3 +247,157 @@ int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid,
 
     return 0;
 }
+
+struct QEMUCPUSegment {
+    uint32_t selector;
+    uint32_t limit;
+    uint32_t flags;
+    uint32_t pad;
+    uint64_t base;
+};
+
+typedef struct QEMUCPUSegment QEMUCPUSegment;
+
+struct QEMUCPUState {
+    uint32_t version;
+    uint32_t size;
+    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
+    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
+    uint64_t rip, rflags;
+    QEMUCPUSegment cs, ds, es, fs, gs, ss;
+    QEMUCPUSegment ldt, tr, gdt, idt;
+    uint64_t cr[5];
+};
+
+typedef struct QEMUCPUState QEMUCPUState;
+
+static void copy_segment(QEMUCPUSegment *d, SegmentCache *s)
+{
+    d->pad = 0;
+    d->selector = s->selector;
+    d->limit = s->limit;
+    d->flags = s->flags;
+    d->base = s->base;
+}
+
+static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
+{
+    memset(s, 0, sizeof(QEMUCPUState));
+
+    s->version = 1;
+    s->size = sizeof(QEMUCPUState);
+
+    s->rax = env->regs[R_EAX];
+    s->rbx = env->regs[R_EBX];
+    s->rcx = env->regs[R_ECX];
+    s->rdx = env->regs[R_EDX];
+    s->rsi = env->regs[R_ESI];
+    s->rdi = env->regs[R_EDI];
+    s->rsp = env->regs[R_ESP];
+    s->rbp = env->regs[R_EBP];
+#ifdef TARGET_X86_64
+    s->r8  = env->regs[8];
+    s->r9  = env->regs[9];
+    s->r10 = env->regs[10];
+    s->r11 = env->regs[11];
+    s->r12 = env->regs[12];
+    s->r13 = env->regs[13];
+    s->r14 = env->regs[14];
+    s->r15 = env->regs[15];
+#endif
+    s->rip = env->eip;
+    s->rflags = env->eflags;
+
+    copy_segment(&s->cs, &env->segs[R_CS]);
+    copy_segment(&s->ds, &env->segs[R_DS]);
+    copy_segment(&s->es, &env->segs[R_ES]);
+    copy_segment(&s->fs, &env->segs[R_FS]);
+    copy_segment(&s->gs, &env->segs[R_GS]);
+    copy_segment(&s->ss, &env->segs[R_SS]);
+    copy_segment(&s->ldt, &env->ldt);
+    copy_segment(&s->tr, &env->tr);
+    copy_segment(&s->gdt, &env->gdt);
+    copy_segment(&s->idt, &env->idt);
+
+    s->cr[0] = env->cr[0];
+    s->cr[1] = env->cr[1];
+    s->cr[2] = env->cr[2];
+    s->cr[3] = env->cr[3];
+    s->cr[4] = env->cr[4];
+}
+
+int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    QEMUCPUState state;
+    Elf64_Nhdr *note;
+    char *buf;
+    int descsz, note_size, name_size = 5;
+    const char *name = "QEMU";
+    int ret;
+
+    qemu_get_cpustate(&state, env);
+
+    descsz = sizeof(state);
+    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+                (descsz + 3) / 4) * 4;
+    note = g_malloc(note_size);
+
+    memset(note, 0, note_size);
+    note->n_namesz = cpu_to_le32(name_size);
+    note->n_descsz = cpu_to_le32(descsz);
+    note->n_type = 0;
+    buf = (char *)note;
+    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
+    memcpy(buf, name, name_size);
+    buf += ((name_size + 3) / 4) * 4;
+    memcpy(buf, &state, sizeof(state));
+
+    ret = f(*offset, note, note_size, opaque);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}
+
+int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    QEMUCPUState state;
+    Elf32_Nhdr *note;
+    char *buf;
+    int descsz, note_size, name_size = 5;
+    const char *name = "QEMU";
+    int ret;
+
+    qemu_get_cpustate(&state, env);
+
+    descsz = sizeof(state);
+    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+                (descsz + 3) / 4) * 4;
+    note = g_malloc(note_size);
+
+    memset(note, 0, note_size);
+    note->n_namesz = cpu_to_le32(name_size);
+    note->n_descsz = cpu_to_le32(descsz);
+    note->n_type = 0;
+    buf = (char *)note;
+    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
+    memcpy(buf, name, name_size);
+    buf += ((name_size + 3) / 4) * 4;
+    memcpy(buf, &state, sizeof(state));
+
+    ret = f(*offset, note, note_size, opaque);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 07/14 v7] target-i386: add API to get dump info
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (5 preceding siblings ...)
  2012-03-01  2:48 ` [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status " Wen Congyang
@ 2012-03-01  2:49 ` Wen Congyang
  2012-03-01  2:50 ` [Qemu-devel] [RFC][PATCH 08/14 v7] make gdb_id() generally avialable Wen Congyang
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:49 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

Dump info contains: endian, class and architecture. The next
patch will use these information to create vmcore.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 cpu-all.h               |    7 +++++++
 dump.h                  |   23 +++++++++++++++++++++++
 target-i386/arch_dump.c |   34 ++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+), 0 deletions(-)
 create mode 100644 dump.h

diff --git a/cpu-all.h b/cpu-all.h
index ad69269..a77f9e8 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -23,6 +23,7 @@
 #include "qemu-tls.h"
 #include "cpu-common.h"
 #include "memory_mapping.h"
+#include "dump.h"
 
 /* some important defines:
  *
@@ -544,6 +545,7 @@ int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
                              target_phys_addr_t *offset, void *opaque);
 int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
                              target_phys_addr_t *offset, void *opaque);
+int cpu_get_dump_info(ArchDumpInfo *info);
 #else
 static inline int cpu_write_elf64_note(write_core_dump_function f,
                                        CPUState *env, int cpuid,
@@ -574,6 +576,11 @@ static inline int cpu_write_elf32_qemunote(write_core_dump_function f,
 {
     return -1;
 }
+
+static inline int cpu_get_dump_info(ArchDumpInfo *info)
+{
+    return -1;
+}
 #endif
 
 #endif /* CPU_ALL_H */
diff --git a/dump.h b/dump.h
new file mode 100644
index 0000000..28340cf
--- /dev/null
+++ b/dump.h
@@ -0,0 +1,23 @@
+/*
+ * QEMU dump
+ *
+ * Copyright Fujitsu, Corp. 2011, 2012
+ *
+ * Authors:
+ *     Wen Congyang <wency@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef DUMP_H
+#define DUMP_H
+
+typedef struct ArchDumpInfo {
+    int d_machine;  /* Architecture */
+    int d_endian;   /* ELFDATA2LSB or ELFDATA2MSB */
+    int d_class;    /* ELFCLASS32 or ELFCLASS64 */
+} ArchDumpInfo;
+
+#endif
diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c
index 560c8a3..e4351f4 100644
--- a/target-i386/arch_dump.c
+++ b/target-i386/arch_dump.c
@@ -13,6 +13,7 @@
 
 #include "cpu.h"
 #include "cpu-all.h"
+#include "dump.h"
 #include "elf.h"
 
 #ifdef TARGET_X86_64
@@ -401,3 +402,36 @@ int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
 
     return 0;
 }
+
+int cpu_get_dump_info(ArchDumpInfo *info)
+{
+    bool lma = false;
+    RAMBlock *block;
+
+#ifdef TARGET_X86_64
+    lma = !!(first_cpu->hflags & HF_LMA_MASK);
+#endif
+
+    if (lma) {
+        info->d_machine = EM_X86_64;
+    } else {
+        info->d_machine = EM_386;
+    }
+    info->d_endian = ELFDATA2LSB;
+
+    if (lma) {
+        info->d_class = ELFCLASS64;
+    } else {
+        info->d_class = ELFCLASS32;
+
+        QLIST_FOREACH(block, &ram_list.blocks, next) {
+            if (block->offset + block->length > UINT_MAX) {
+                /* The memory size is greater than 4G */
+                info->d_class = ELFCLASS64;
+                break;
+            }
+        }
+    }
+
+    return 0;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 08/14 v7] make gdb_id() generally avialable
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (6 preceding siblings ...)
  2012-03-01  2:49 ` [Qemu-devel] [RFC][PATCH 07/14 v7] target-i386: add API to get dump info Wen Congyang
@ 2012-03-01  2:50 ` Wen Congyang
  2012-03-01  2:51 ` [Qemu-devel] [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:50 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

The following patch also needs this API, so make it generally avialable

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 gdbstub.c |    9 ---------
 gdbstub.h |    9 +++++++++
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 7d470b6..046b036 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1939,15 +1939,6 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 #endif
 }
 
-static inline int gdb_id(CPUState *env)
-{
-#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL)
-    return env->host_tid;
-#else
-    return env->cpu_index + 1;
-#endif
-}
-
 static CPUState *find_cpu(uint32_t thread_id)
 {
     CPUState *env;
diff --git a/gdbstub.h b/gdbstub.h
index d82334f..f30bfe8 100644
--- a/gdbstub.h
+++ b/gdbstub.h
@@ -30,6 +30,15 @@ void gdb_register_coprocessor(CPUState *env,
                               gdb_reg_cb get_reg, gdb_reg_cb set_reg,
                               int num_regs, const char *xml, int g_pos);
 
+static inline int gdb_id(CPUState *env)
+{
+#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL)
+    return env->host_tid;
+#else
+    return env->cpu_index + 1;
+#endif
+}
+
 #endif
 
 #ifdef CONFIG_USER_ONLY
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (7 preceding siblings ...)
  2012-03-01  2:50 ` [Qemu-devel] [RFC][PATCH 08/14 v7] make gdb_id() generally avialable Wen Congyang
@ 2012-03-01  2:51 ` Wen Congyang
  2012-03-01  7:04   ` HATAYAMA Daisuke
  2012-03-01  2:52 ` [Qemu-devel] [RFC][PATCH 10/14 v7] support to cancel the current dumping Wen Congyang
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:51 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 Makefile.target  |    2 +-
 dump.c           |  637 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hmp-commands.hx  |   20 ++
 hmp.c            |    9 +
 hmp.h            |    1 +
 qapi-schema.json |   13 ++
 qmp-commands.hx  |   29 +++
 7 files changed, 710 insertions(+), 1 deletions(-)
 create mode 100644 dump.c

diff --git a/Makefile.target b/Makefile.target
index cfd3113..4ae59f5 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -210,7 +210,7 @@ obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-$(CONFIG_VGA) += vga.o
 obj-y += memory.o savevm.o
 obj-y += memory_mapping.o
-obj-$(CONFIG_HAVE_CORE_DUMP) += arch_dump.o
+obj-$(CONFIG_HAVE_CORE_DUMP) += arch_dump.o dump.o
 LIBS+=-lz
 
 obj-i386-$(CONFIG_KVM) += hyperv.o
diff --git a/dump.c b/dump.c
new file mode 100644
index 0000000..c9baedb
--- /dev/null
+++ b/dump.c
@@ -0,0 +1,637 @@
+/*
+ * QEMU dump
+ *
+ * Copyright Fujitsu, Corp. 2011
+ *
+ * Authors:
+ *     Wen Congyang <wency@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include <unistd.h>
+#include "elf.h"
+#include <sys/procfs.h>
+#include <glib.h>
+#include "cpu.h"
+#include "cpu-all.h"
+#include "targphys.h"
+#include "monitor.h"
+#include "kvm.h"
+#include "dump.h"
+#include "sysemu.h"
+#include "bswap.h"
+#include "memory_mapping.h"
+#include "error.h"
+#include "qmp-commands.h"
+#include "gdbstub.h"
+
+static inline uint16_t cpu_contert_to_target16(uint16_t val, int endian)
+{
+    if (endian == ELFDATA2LSB) {
+        val = cpu_to_le16(val);
+    } else {
+        val = cpu_to_be16(val);
+    }
+
+    return val;
+}
+
+static inline uint32_t cpu_contert_to_target32(uint32_t val, int endian)
+{
+    if (endian == ELFDATA2LSB) {
+        val = cpu_to_le32(val);
+    } else {
+        val = cpu_to_be32(val);
+    }
+
+    return val;
+}
+
+static inline uint64_t cpu_contert_to_target64(uint64_t val, int endian)
+{
+    if (endian == ELFDATA2LSB) {
+        val = cpu_to_le64(val);
+    } else {
+        val = cpu_to_be64(val);
+    }
+
+    return val;
+}
+
+enum {
+    DUMP_STATE_ERROR,
+    DUMP_STATE_SETUP,
+    DUMP_STATE_CANCELLED,
+    DUMP_STATE_ACTIVE,
+    DUMP_STATE_COMPLETED,
+};
+
+typedef struct DumpState {
+    ArchDumpInfo dump_info;
+    MemoryMappingList list;
+    int phdr_num;
+    int state;
+    bool resume;
+    char *error;
+    target_phys_addr_t memory_offset;
+    write_core_dump_function f;
+    void (*cleanup)(void *opaque);
+    void *opaque;
+} DumpState;
+
+static DumpState *dump_get_current(void)
+{
+    static DumpState current_dump = {
+        .state = DUMP_STATE_SETUP,
+    };
+
+    return &current_dump;
+}
+
+static int dump_cleanup(DumpState *s)
+{
+    int ret = 0;
+
+    memory_mapping_list_free(&s->list);
+    s->cleanup(s->opaque);
+    if (s->resume) {
+        vm_start();
+    }
+
+    return ret;
+}
+
+static void dump_error(DumpState *s, const char *reason)
+{
+    s->state = DUMP_STATE_ERROR;
+    s->error = g_strdup(reason);
+    dump_cleanup(s);
+}
+
+static int write_elf64_header(DumpState *s)
+{
+    Elf64_Ehdr elf_header;
+    int ret;
+    int endian = s->dump_info.d_endian;
+
+    memset(&elf_header, 0, sizeof(Elf64_Ehdr));
+    memcpy(&elf_header, ELFMAG, 4);
+    elf_header.e_ident[EI_CLASS] = ELFCLASS64;
+    elf_header.e_ident[EI_DATA] = s->dump_info.d_endian;
+    elf_header.e_ident[EI_VERSION] = EV_CURRENT;
+    elf_header.e_type = cpu_contert_to_target16(ET_CORE, endian);
+    elf_header.e_machine = cpu_contert_to_target16(s->dump_info.d_machine,
+                                                   endian);
+    elf_header.e_version = cpu_contert_to_target32(EV_CURRENT, endian);
+    elf_header.e_ehsize = cpu_contert_to_target16(sizeof(elf_header), endian);
+    elf_header.e_phoff = cpu_contert_to_target64(sizeof(Elf64_Ehdr), endian);
+    elf_header.e_phentsize = cpu_contert_to_target16(sizeof(Elf64_Phdr), endian);
+    elf_header.e_phnum = cpu_contert_to_target16(s->phdr_num, endian);
+
+    ret = s->f(0, &elf_header, sizeof(elf_header), s->opaque);
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write elf header.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf32_header(DumpState *s)
+{
+    Elf32_Ehdr elf_header;
+    int ret;
+    int endian = s->dump_info.d_endian;
+
+    memset(&elf_header, 0, sizeof(Elf32_Ehdr));
+    memcpy(&elf_header, ELFMAG, 4);
+    elf_header.e_ident[EI_CLASS] = ELFCLASS32;
+    elf_header.e_ident[EI_DATA] = endian;
+    elf_header.e_ident[EI_VERSION] = EV_CURRENT;
+    elf_header.e_type = cpu_contert_to_target16(ET_CORE, endian);
+    elf_header.e_machine = cpu_contert_to_target16(s->dump_info.d_machine,
+                                                   endian);
+    elf_header.e_version = cpu_contert_to_target32(EV_CURRENT, endian);
+    elf_header.e_ehsize = cpu_contert_to_target16(sizeof(elf_header), endian);
+    elf_header.e_phoff = cpu_contert_to_target32(sizeof(Elf32_Ehdr), endian);
+    elf_header.e_phentsize = cpu_contert_to_target16(sizeof(Elf32_Phdr),
+                                                     endian);
+    elf_header.e_phnum = cpu_contert_to_target16(s->phdr_num, endian);
+
+    ret = s->f(0, &elf_header, sizeof(elf_header), s->opaque);
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write elf header.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
+                            int phdr_index, target_phys_addr_t offset)
+{
+    Elf64_Phdr phdr;
+    off_t phdr_offset;
+    int ret;
+    int endian = s->dump_info.d_endian;
+
+    memset(&phdr, 0, sizeof(Elf64_Phdr));
+    phdr.p_type = cpu_contert_to_target32(PT_LOAD, endian);
+    phdr.p_offset = cpu_contert_to_target64(offset, endian);
+    phdr.p_paddr = cpu_contert_to_target64(memory_mapping->phys_addr, endian);
+    if (offset == -1) {
+        phdr.p_filesz = 0;
+    } else {
+        phdr.p_filesz = cpu_contert_to_target64(memory_mapping->length, endian);
+    }
+    phdr.p_memsz = cpu_contert_to_target64(memory_mapping->length, endian);
+    phdr.p_vaddr = cpu_contert_to_target64(memory_mapping->virt_addr, endian);
+
+    phdr_offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_index;
+    ret = s->f(phdr_offset, &phdr, sizeof(Elf64_Phdr), s->opaque);
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write program header table.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
+                            int phdr_index, target_phys_addr_t offset)
+{
+    Elf32_Phdr phdr;
+    off_t phdr_offset;
+    int ret;
+    int endian = s->dump_info.d_endian;
+
+    memset(&phdr, 0, sizeof(Elf32_Phdr));
+    phdr.p_type = cpu_contert_to_target32(PT_LOAD, endian);
+    phdr.p_offset = cpu_contert_to_target32(offset, endian);
+    phdr.p_paddr = cpu_contert_to_target32(memory_mapping->phys_addr, endian);
+    if (offset == -1) {
+        phdr.p_filesz = 0;
+    } else {
+        phdr.p_filesz = cpu_contert_to_target32(memory_mapping->length, endian);
+    }
+    phdr.p_memsz = cpu_contert_to_target32(memory_mapping->length, endian);
+    phdr.p_vaddr = cpu_contert_to_target32(memory_mapping->virt_addr, endian);
+
+    phdr_offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_index;
+    ret = s->f(phdr_offset, &phdr, sizeof(Elf32_Phdr), s->opaque);
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write program header table.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf64_notes(DumpState *s, int phdr_index,
+                             target_phys_addr_t *offset)
+{
+    CPUState *env;
+    int ret;
+    target_phys_addr_t begin = *offset;
+    Elf64_Phdr phdr;
+    off_t phdr_offset;
+    int id;
+    int endian = s->dump_info.d_endian;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        id = gdb_id(env);
+        ret = cpu_write_elf64_note(s->f, env, id, offset, s->opaque);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write elf notes.\n");
+            return -1;
+        }
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        ret = cpu_write_elf64_qemunote(s->f, env, offset, s->opaque);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write CPU status.\n");
+            return -1;
+        }
+    }
+
+    memset(&phdr, 0, sizeof(Elf64_Phdr));
+    phdr.p_type = cpu_contert_to_target32(PT_NOTE, endian);
+    phdr.p_offset = cpu_contert_to_target64(begin, endian);
+    phdr.p_paddr = 0;
+    phdr.p_filesz = cpu_contert_to_target64(*offset - begin, endian);
+    phdr.p_memsz = cpu_contert_to_target64(*offset - begin, endian);
+    phdr.p_vaddr = 0;
+
+    phdr_offset = sizeof(Elf64_Ehdr);
+    ret = s->f(phdr_offset, &phdr, sizeof(Elf64_Phdr), s->opaque);
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write program header table.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_elf32_notes(DumpState *s, int phdr_index,
+                             target_phys_addr_t *offset)
+{
+    CPUState *env;
+    int ret;
+    target_phys_addr_t begin = *offset;
+    Elf32_Phdr phdr;
+    off_t phdr_offset;
+    int id;
+    int endian = s->dump_info.d_endian;
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        id = gdb_id(env);
+        ret = cpu_write_elf32_note(s->f, env, id, offset, s->opaque);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write elf notes.\n");
+            return -1;
+        }
+    }
+
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        ret = cpu_write_elf32_qemunote(s->f, env, offset, s->opaque);
+        if (ret < 0) {
+            dump_error(s, "dump: failed to write CPU status.\n");
+            return -1;
+        }
+    }
+
+    memset(&phdr, 0, sizeof(Elf32_Phdr));
+    phdr.p_type = cpu_contert_to_target32(PT_NOTE, endian);
+    phdr.p_offset = cpu_contert_to_target32(begin, endian);
+    phdr.p_paddr = 0;
+    phdr.p_filesz = cpu_contert_to_target32(*offset - begin, endian);
+    phdr.p_memsz = cpu_contert_to_target32(*offset - begin, endian);
+    phdr.p_vaddr = 0;
+
+    phdr_offset = sizeof(Elf32_Ehdr);
+    ret = s->f(phdr_offset, &phdr, sizeof(Elf32_Phdr), s->opaque);
+    if (ret < 0) {
+        dump_error(s, "dump: failed to write program header table.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_data(DumpState *s, void *buf, int length,
+                      target_phys_addr_t *offset)
+{
+    int ret;
+
+    ret = s->f(*offset, buf, length, s->opaque);
+    if (ret < 0) {
+        dump_error(s, "dump: failed to save memory.\n");
+        return -1;
+    }
+
+    *offset += length;
+    return 0;
+}
+
+/* write the memroy to vmcore. 1 page per I/O. */
+static int write_memory(DumpState *s, RAMBlock *block,
+                        target_phys_addr_t *offset)
+{
+    int i, ret;
+
+    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
+        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
+                         TARGET_PAGE_SIZE, offset);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+
+    if ((block->length % TARGET_PAGE_SIZE) != 0) {
+        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
+                         block->length % TARGET_PAGE_SIZE, offset);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/* get the memory's offset in the vmcore */
+static target_phys_addr_t get_offset(target_phys_addr_t phys_addr,
+                                     target_phys_addr_t memory_offset)
+{
+    RAMBlock *block;
+    target_phys_addr_t offset = memory_offset;
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (phys_addr >= block->offset &&
+            phys_addr < block->offset + block->length) {
+            return phys_addr - block->offset + offset;
+        }
+        offset += block->length;
+    }
+
+    return -1;
+}
+
+/* write elf header, PT_NOTE and elf note to vmcore. */
+static int dump_begin(DumpState *s)
+{
+    target_phys_addr_t offset;
+    int ret;
+
+    s->state = DUMP_STATE_ACTIVE;
+
+    /*
+     * the vmcore's format is:
+     *   --------------
+     *   |  elf header |
+     *   --------------
+     *   |  PT_NOTE    |
+     *   --------------
+     *   |  PT_LOAD    |
+     *   --------------
+     *   |  ......     |
+     *   --------------
+     *   |  PT_LOAD    |
+     *   --------------
+     *   |  elf note   |
+     *   --------------
+     *   |  memory     |
+     *   --------------
+     *
+     * we only know where the memory is saved after we write elf note into
+     * vmcore.
+     */
+
+    /* write elf header to vmcore */
+    if (s->dump_info.d_class == ELFCLASS64) {
+        ret = write_elf64_header(s);
+    } else {
+        ret = write_elf32_header(s);
+    }
+    if (ret < 0) {
+        return -1;
+    }
+
+    /* write elf notes to vmcore */
+    if (s->dump_info.d_class == ELFCLASS64) {
+        offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*s->phdr_num;
+        ret = write_elf64_notes(s, 0, &offset);
+    } else {
+        offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*s->phdr_num;
+        ret = write_elf32_notes(s, 0, &offset);
+    }
+
+    if (ret < 0) {
+        return -1;
+    }
+
+    s->memory_offset = offset;
+    return 0;
+}
+
+/* write PT_LOAD to vmcore */
+static int dump_completed(DumpState *s)
+{
+    target_phys_addr_t offset;
+    MemoryMapping *memory_mapping;
+    int phdr_index = 1, ret;
+
+    QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
+        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
+        if (s->dump_info.d_class == ELFCLASS64) {
+            ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
+        } else {
+            ret = write_elf32_load(s, memory_mapping, phdr_index++, offset);
+        }
+        if (ret < 0) {
+            return -1;
+        }
+    }
+
+    s->state = DUMP_STATE_COMPLETED;
+    dump_cleanup(s);
+    return 0;
+}
+
+/* write all memory to vmcore */
+static int dump_iterate(DumpState *s)
+{
+    RAMBlock *block;
+    target_phys_addr_t offset = s->memory_offset;
+    int ret;
+
+    /* write all memory to vmcore */
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        ret = write_memory(s, block, &offset);
+        if (ret < 0) {
+            return -1;
+        }
+    }
+
+    return dump_completed(s);
+}
+
+static int create_vmcore(DumpState *s)
+{
+    int ret;
+
+    ret = dump_begin(s);
+    if (ret < 0) {
+        return -1;
+    }
+
+    ret = dump_iterate(s);
+    if (ret < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static DumpState *dump_init(Error **errp)
+{
+    CPUState *env;
+    DumpState *s = dump_get_current();
+    int ret;
+
+    if (runstate_is_running()) {
+        vm_stop(RUN_STATE_PAUSED);
+        s->resume = true;
+    } else {
+        s->resume = false;
+    }
+    s->state = DUMP_STATE_SETUP;
+    if (s->error) {
+        g_free(s->error);
+        s->error = NULL;
+    }
+
+    /*
+     * 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 register before we get dump
+     * info.
+     */
+    for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu_synchronize_state(env);
+    }
+
+    ret = cpu_get_dump_info(&s->dump_info);
+    if (ret < 0) {
+        error_set(errp, QERR_UNSUPPORTED);
+        return NULL;
+    }
+
+    /* get memory mapping */
+    memory_mapping_list_init(&s->list);
+    qemu_get_guest_memory_mapping(&s->list);
+
+    /*
+     * calculate phdr_num
+     *
+     * the type of phdr->num is uint16_t, so we should avoid overflow
+     */
+    s->phdr_num = 1; /* PT_NOTE */
+    if (s->list.num > (1 << 16) - 2) {
+        s->phdr_num = (1 << 16) - 1;
+    } else {
+        s->phdr_num += s->list.num;
+    }
+
+    return s;
+}
+
+static int fd_write_vmcore(target_phys_addr_t offset, void *buf, size_t size,
+                           void *opaque)
+{
+    int fd = (int)(intptr_t)opaque;
+    int ret;
+
+    ret = lseek(fd, offset, SEEK_SET);
+    if (ret < 0) {
+        return -1;
+    }
+
+    ret = write(fd, buf, size);
+    if (ret != size) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static void fd_cleanup(void *opaque)
+{
+    int fd = (int)(intptr_t)opaque;
+
+    if (fd != -1) {
+        close(fd);
+    }
+}
+
+static DumpState *dump_init_fd(int fd, Error **errp)
+{
+    DumpState *s = dump_init(errp);
+
+    if (s == NULL) {
+        return NULL;
+    }
+
+    s->f = fd_write_vmcore;
+    s->cleanup = fd_cleanup;
+    s->opaque = (void *)(intptr_t)fd;
+
+    return s;
+}
+
+void qmp_dump(const char *file, Error **errp)
+{
+    const char *p;
+    int fd = -1;
+    DumpState *s;
+
+#if !defined(WIN32)
+    if (strstart(file, "fd:", &p)) {
+        fd = qemu_get_fd(p);
+        if (fd == -1) {
+            error_set(errp, QERR_FD_NOT_FOUND, p);
+            return;
+        }
+    }
+#endif
+
+    if  (strstart(file, "file:", &p)) {
+        fd = open(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR);
+        if (fd < 0) {
+            error_set(errp, QERR_OPEN_FILE_FAILED, p);
+            return;
+        }
+    }
+
+    if (fd == -1) {
+        error_set(errp, QERR_INVALID_PARAMETER, "file");
+        return;
+    }
+
+    s = dump_init_fd(fd, errp);
+    if (!s) {
+        return;
+    }
+
+    if (create_vmcore(s) < 0) {
+        error_set(errp, QERR_IO_ERROR);
+    }
+
+    return;
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 64b3656..19200ad 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -880,6 +880,26 @@ server will ask the spice/vnc client to automatically reconnect using the
 new parameters (if specified) once the vm migration finished successfully.
 ETEXI
 
+#if defined(CONFIG_HAVE_CORE_DUMP)
+    {
+        .name       = "dump",
+        .args_type  = "file:s",
+        .params     = "file",
+        .help       = "dump to file",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd = hmp_dump,
+    },
+
+
+STEXI
+@item dump @var{file}
+@findex dump
+Dump to @var{file}. The file can be processed with crash or gdb.
+    file: destination file(started with "file:") or destination file descriptor
+          (started with "fd:")
+ETEXI
+#endif
+
     {
         .name       = "snapshot_blkdev",
         .args_type  = "device:B,snapshot-file:s?,format:s?",
diff --git a/hmp.c b/hmp.c
index 3a54455..309ccec 100644
--- a/hmp.c
+++ b/hmp.c
@@ -856,3 +856,12 @@ void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
 
     hmp_handle_error(mon, &error);
 }
+
+void hmp_dump(Monitor *mon, const QDict *qdict)
+{
+    Error *errp = NULL;
+    const char *file = qdict_get_str(qdict, "file");
+
+    qmp_dump(file, &errp);
+    hmp_handle_error(mon, &errp);
+}
diff --git a/hmp.h b/hmp.h
index 5409464..b055e50 100644
--- a/hmp.h
+++ b/hmp.h
@@ -59,5 +59,6 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
 void hmp_block_stream(Monitor *mon, const QDict *qdict);
 void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
+void hmp_dump(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index d0b6792..3c4aa70 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1593,3 +1593,16 @@
 { 'command': 'qom-list-types',
   'data': { '*implements': 'str', '*abstract': 'bool' },
   'returns': [ 'ObjectTypeInfo' ] }
+
+##
+# @dump
+#
+# Dump guest's memory to vmcore.
+#
+# @file: the filename or file descriptor of the vmcore.
+#
+# Returns: nothing on success
+#
+# Since: 1.1
+##
+{ 'command': 'dump', 'data': { 'file': 'str' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 705f704..1199316 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -586,6 +586,35 @@ Example:
 
 EQMP
 
+#if defined(CONFIG_HAVE_CORE_DUMP)
+    {
+        .name       = "dump",
+        .args_type  = "file:s",
+        .params     = "file",
+        .help       = "dump to file",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = qmp_marshal_input_dump,
+    },
+
+SQMP
+dump
+
+
+Dump to file. The file can be processed with crash or gdb.
+
+Arguments:
+
+- "file": destination file(started with "file:") or destination file descriptor
+          (started with "fd:") (json-string)
+
+Example:
+
+-> { "execute": "dump", "arguments": { "file": "fd:dump" } }
+<- { "return": {} }
+
+EQMP
+#endif
+
     {
         .name       = "netdev_add",
         .args_type  = "netdev:O",
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 10/14 v7] support to cancel the current dumping
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (8 preceding siblings ...)
  2012-03-01  2:51 ` [Qemu-devel] [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
@ 2012-03-01  2:52 ` Wen Congyang
  2012-03-01  2:53 ` [Qemu-devel] [RFC][PATCH 11/14 v7] support to query dumping status Wen Congyang
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:52 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

Add API to allow the user to cancel the current dumping.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c           |   13 +++++++++++++
 hmp-commands.hx  |   14 ++++++++++++++
 hmp.c            |    5 +++++
 hmp.h            |    1 +
 qapi-schema.json |   13 +++++++++++++
 qmp-commands.hx  |   21 +++++++++++++++++++++
 6 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/dump.c b/dump.c
index c9baedb..673720f 100644
--- a/dump.c
+++ b/dump.c
@@ -635,3 +635,16 @@ void qmp_dump(const char *file, Error **errp)
 
     return;
 }
+
+void qmp_dump_cancel(Error **errp)
+{
+    DumpState *s = dump_get_current();
+
+    if (s->state != DUMP_STATE_ACTIVE) {
+        return;
+    }
+
+    s->state = DUMP_STATE_CANCELLED;
+    dump_cleanup(s);
+    return;
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 19200ad..e6db6b6 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -901,6 +901,20 @@ ETEXI
 #endif
 
     {
+        .name       = "dump_cancel",
+        .args_type  = "",
+        .params     = "",
+        .help       = "cancel the current VM dumping",
+        .mhandler.cmd = hmp_dump_cancel,
+    },
+
+STEXI
+@item dump_cancel
+@findex dump_cancel
+Cancel the current VM dumping.
+ETEXI
+
+    {
         .name       = "snapshot_blkdev",
         .args_type  = "device:B,snapshot-file:s?,format:s?",
         .params     = "device [new-image-file] [format]",
diff --git a/hmp.c b/hmp.c
index 309ccec..a20a7b0 100644
--- a/hmp.c
+++ b/hmp.c
@@ -865,3 +865,8 @@ void hmp_dump(Monitor *mon, const QDict *qdict)
     qmp_dump(file, &errp);
     hmp_handle_error(mon, &errp);
 }
+
+void hmp_dump_cancel(Monitor *mon, const QDict *qdict)
+{
+    qmp_dump_cancel(NULL);
+}
diff --git a/hmp.h b/hmp.h
index b055e50..75c6c1d 100644
--- a/hmp.h
+++ b/hmp.h
@@ -60,5 +60,6 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict);
 void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
 void hmp_dump(Monitor *mon, const QDict *qdict);
+void hmp_dump_cancel(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 3c4aa70..a764cd3 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1606,3 +1606,16 @@
 # Since: 1.1
 ##
 { 'command': 'dump', 'data': { 'file': 'str' } }
+
+##
+# @dump_cancel
+#
+# Cancel the current executing dumping process.
+#
+# Returns: nothing on success
+#
+# Notes: This command succeeds even if there is no dumping process running.
+#
+# Since: 1.1
+##
+{ 'command': 'dump_cancel' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 1199316..a2d94a9 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -616,6 +616,27 @@ EQMP
 #endif
 
     {
+        .name       = "dump_cancel",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_dump_cancel,
+    },
+
+SQMP
+dump_cancel
+
+
+Cancel the current dumping.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "dump_cancel" }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "netdev_add",
         .args_type  = "netdev:O",
         .params     = "[user|tap|socket],id=str[,prop=value][,...]",
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 11/14 v7] support to query dumping status
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (9 preceding siblings ...)
  2012-03-01  2:52 ` [Qemu-devel] [RFC][PATCH 10/14 v7] support to cancel the current dumping Wen Congyang
@ 2012-03-01  2:53 ` Wen Congyang
  2012-03-01  2:54 ` [Qemu-devel] [RFC][PATCH 12/14 v7] run dump at the background Wen Congyang
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:53 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

Add API to allow the user to query dumping status.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c           |   32 ++++++++++++++++++++++++++++++++
 hmp-commands.hx  |    2 ++
 hmp.c            |   17 +++++++++++++++++
 hmp.h            |    1 +
 monitor.c        |    7 +++++++
 qapi-schema.json |   26 ++++++++++++++++++++++++++
 qmp-commands.hx  |   52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 137 insertions(+), 0 deletions(-)

diff --git a/dump.c b/dump.c
index 673720f..48779d8 100644
--- a/dump.c
+++ b/dump.c
@@ -648,3 +648,35 @@ void qmp_dump_cancel(Error **errp)
     dump_cleanup(s);
     return;
 }
+
+DumpInfo *qmp_query_dump(Error **errp)
+{
+    DumpInfo *info = g_malloc0(sizeof(*info));
+    DumpState *s = dump_get_current();
+
+    switch (s->state) {
+    case DUMP_STATE_SETUP:
+        /* no migration has happened ever */
+        break;
+    case DUMP_STATE_ACTIVE:
+        info->has_status = true;
+        info->status = g_strdup("active");
+        break;
+    case DUMP_STATE_COMPLETED:
+        info->has_status = true;
+        info->status = g_strdup("completed");
+        break;
+    case DUMP_STATE_ERROR:
+        info->has_status = true;
+        info->status = g_strdup("failed");
+        info->has_error = true;
+        info->error = g_strdup(s->error);
+        break;
+    case DUMP_STATE_CANCELLED:
+        info->has_status = true;
+        info->status = g_strdup("cancelled");
+        break;
+    }
+
+    return info;
+}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index e6db6b6..0c0a7b4 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1434,6 +1434,8 @@ show device tree
 show qdev device model list
 @item info roms
 show roms
+@item info dump
+show dumping status
 @end table
 ETEXI
 
diff --git a/hmp.c b/hmp.c
index a20a7b0..476d355 100644
--- a/hmp.c
+++ b/hmp.c
@@ -870,3 +870,20 @@ void hmp_dump_cancel(Monitor *mon, const QDict *qdict)
 {
     qmp_dump_cancel(NULL);
 }
+
+void hmp_info_dump(Monitor *mon)
+{
+    DumpInfo *info;
+
+    info = qmp_query_dump(NULL);
+
+    if (info->has_status) {
+        monitor_printf(mon, "Dumping status: %s\n", info->status);
+    }
+
+    if (info->has_error) {
+        monitor_printf(mon, "Dumping failed reason: %s\n", info->error);
+    }
+
+    qapi_free_DumpInfo(info);
+}
diff --git a/hmp.h b/hmp.h
index 75c6c1d..3d105a9 100644
--- a/hmp.h
+++ b/hmp.h
@@ -61,5 +61,6 @@ void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
 void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
 void hmp_dump(Monitor *mon, const QDict *qdict);
 void hmp_dump_cancel(Monitor *mon, const QDict *qdict);
+void hmp_info_dump(Monitor *mon);
 
 #endif
diff --git a/monitor.c b/monitor.c
index 96af5e0..f240895 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2603,6 +2603,13 @@ static mon_cmd_t info_cmds[] = {
         .mhandler.info = do_trace_print_events,
     },
     {
+        .name       = "dump",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show dumping status",
+        .mhandler.info = hmp_info_dump,
+    },
+    {
         .name       = NULL,
     },
 };
diff --git a/qapi-schema.json b/qapi-schema.json
index a764cd3..1e9af32 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1619,3 +1619,29 @@
 # Since: 1.1
 ##
 { 'command': 'dump_cancel' }
+
+##
+# @DumpInfo
+#
+# Information about current migration process.
+#
+# @status: #optional string describing the current dumping status.
+#          As of 1,1 this can be 'active', 'completed', 'failed' or
+#          'cancelled'. If this field is not returned, no migration process
+#          has been initiated
+#
+# Since: 1.1
+##
+{ 'type': 'DumpInfo',
+  'data': { '*status': 'str', '*error': 'str' } }
+
+##
+# @query-dump
+#
+# Returns information about current dumping process.
+#
+# Returns: @DumpInfo
+#
+# Since: 1.1
+##
+{ 'command': 'query-dump', 'returns': 'DumpInfo' }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a2d94a9..666f1bc 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -612,6 +612,11 @@ Example:
 -> { "execute": "dump", "arguments": { "file": "fd:dump" } }
 <- { "return": {} }
 
+Notes:
+
+(1) The 'info dump' command should be used to check dumping's progress
+    and final result (this information is provided by the 'status' member)
+
 EQMP
 #endif
 
@@ -2046,6 +2051,53 @@ EQMP
     },
 
 SQMP
+query-dump
+-------------
+
+Dumping status.
+
+Return a json-object.
+
+The main json-object contains the following:
+
+- "status": migration status (json-string)
+     - Possible values: "active", "completed", "failed", "cancelled"
+
+Examples:
+
+1. Before the first migration
+
+-> { "execute": "query-dump" }
+<- { "return": {} }
+
+2. Migration is done and has succeeded
+
+-> { "execute": "query-dump" }
+<- { "return": { "status": "completed" } }
+
+3. Migration is done and has failed
+
+-> { "execute": "query-dump" }
+<- { "return": { "status": "failed" } }
+
+4. Migration is being performed:
+
+-> { "execute": "query-dump" }
+<- {
+      "return":{
+         "status":"active",
+      }
+   }
+
+EQMP
+
+    {
+        .name       = "query-dump",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_dump,
+    },
+
+SQMP
 query-balloon
 -------------
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 12/14 v7] run dump at the background
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (10 preceding siblings ...)
  2012-03-01  2:53 ` [Qemu-devel] [RFC][PATCH 11/14 v7] support to query dumping status Wen Congyang
@ 2012-03-01  2:54 ` Wen Congyang
  2012-03-01  2:55 ` [Qemu-devel] [RFC][PATCH 13/14 v7] support detached dump Wen Congyang
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:54 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

The new monitor command dump may take long time to finish. So we need run it
at the background.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c |  168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 vl.c   |    5 +-
 2 files changed, 150 insertions(+), 23 deletions(-)

diff --git a/dump.c b/dump.c
index 48779d8..8224116 100644
--- a/dump.c
+++ b/dump.c
@@ -78,9 +78,21 @@ typedef struct DumpState {
     bool resume;
     char *error;
     target_phys_addr_t memory_offset;
+
+    /*
+     * Return value:
+     * -2: EAGAIN
+     * -1: error
+     *  0: success
+     */
     write_core_dump_function f;
     void (*cleanup)(void *opaque);
+    int (*dump_begin_iterate)(struct DumpState *, void *opaque);
     void *opaque;
+    RAMBlock *block;
+    ram_addr_t start;
+    target_phys_addr_t offset;
+    VMChangeStateEntry *handler;
 } DumpState;
 
 static DumpState *dump_get_current(void)
@@ -98,6 +110,12 @@ static int dump_cleanup(DumpState *s)
 
     memory_mapping_list_free(&s->list);
     s->cleanup(s->opaque);
+
+    if (s->handler) {
+        qemu_del_vm_change_state_handler(s->handler);
+        s->handler = NULL;
+    }
+
     if (s->resume) {
         vm_start();
     }
@@ -323,40 +341,70 @@ static int write_elf32_notes(DumpState *s, int phdr_index,
     return 0;
 }
 
+/*
+ * Return value:
+ *     -2: blocked
+ *     -1: failed
+ *      0: sucess
+ */
 static int write_data(DumpState *s, void *buf, int length,
                       target_phys_addr_t *offset)
 {
     int ret;
 
     ret = s->f(*offset, buf, length, s->opaque);
-    if (ret < 0) {
+    if (ret == -1) {
         dump_error(s, "dump: failed to save memory.\n");
         return -1;
     }
 
+    if (ret == -2) {
+        return -2;
+    }
+
     *offset += length;
     return 0;
 }
 
 /* write the memroy to vmcore. 1 page per I/O. */
-static int write_memory(DumpState *s, RAMBlock *block,
-                        target_phys_addr_t *offset)
+static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
+                        target_phys_addr_t *offset, int64_t *size,
+                        int64_t deadline)
 {
     int i, ret;
+    int64_t writen_size = 0;
+    int64_t time;
 
-    for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
-        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
+    *size = block->length - start;
+    for (i = 0; i < *size / TARGET_PAGE_SIZE; i++) {
+        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
                          TARGET_PAGE_SIZE, offset);
         if (ret < 0) {
-            return -1;
+            *size = writen_size;
+            return ret;
+        }
+
+        writen_size += TARGET_PAGE_SIZE;
+        time = qemu_get_clock_ms(rt_clock);
+        if (time >= deadline) {
+            /* time out */
+            *size = writen_size;
+            return -2;
         }
     }
 
-    if ((block->length % TARGET_PAGE_SIZE) != 0) {
-        ret = write_data(s, block->host + i * TARGET_PAGE_SIZE,
-                         block->length % TARGET_PAGE_SIZE, offset);
+    if ((*size % TARGET_PAGE_SIZE) != 0) {
+        ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE,
+                         *size % TARGET_PAGE_SIZE, offset);
         if (ret < 0) {
-            return -1;
+            *size = writen_size;
+            return ret;
+        }
+
+        time = qemu_get_clock_ms(rt_clock);
+        if (time >= deadline) {
+            /* time out */
+            return -2;
         }
     }
 
@@ -435,6 +483,7 @@ static int dump_begin(DumpState *s)
     }
 
     s->memory_offset = offset;
+    s->offset = offset;
     return 0;
 }
 
@@ -462,22 +511,65 @@ static int dump_completed(DumpState *s)
     return 0;
 }
 
-/* write all memory to vmcore */
-static int dump_iterate(DumpState *s)
+static int get_next_block(DumpState *s, RAMBlock *block)
 {
+    while (1) {
+        block = QLIST_NEXT(block, next);
+        if (!block) {
+            /* no more block */
+            return 1;
+        }
+
+        s->start = 0;
+        s->block = block;
+
+        return 0;
+    }
+}
+
+/* write memory to vmcore */
+static void dump_iterate(void *opaque)
+{
+    DumpState *s = opaque;
     RAMBlock *block;
-    target_phys_addr_t offset = s->memory_offset;
+    target_phys_addr_t offset = s->offset;
+    int64_t size;
+    int64_t deadline, now;
     int ret;
 
-    /* write all memory to vmcore */
-    QLIST_FOREACH(block, &ram_list.blocks, next) {
-        ret = write_memory(s, block, &offset);
-        if (ret < 0) {
-            return -1;
+    now = qemu_get_clock_ms(rt_clock);
+    deadline = now + 5;
+    while(1) {
+        block = s->block;
+        ret = write_memory(s, block, s->start, &offset, &size, deadline);
+        if (ret == -1) {
+            return;
+        }
+
+        if (ret == -2) {
+            break;
+        }
+
+        ret = get_next_block(s, block);
+        if (ret == 1) {
+            dump_completed(s);
+            return;
         }
     }
 
-    return dump_completed(s);
+    if (size == block->length - s->start) {
+        ret = get_next_block(s, block);
+        if (ret == 1) {
+            dump_completed(s);
+            return;
+        }
+    } else {
+        s->start += size;
+    }
+
+    s->offset = offset;
+
+    return;
 }
 
 static int create_vmcore(DumpState *s)
@@ -489,7 +581,7 @@ static int create_vmcore(DumpState *s)
         return -1;
     }
 
-    ret = dump_iterate(s);
+    ret = s->dump_begin_iterate(s, s->opaque);
     if (ret < 0) {
         return -1;
     }
@@ -497,6 +589,17 @@ static int create_vmcore(DumpState *s)
     return 0;
 }
 
+static void dump_vm_state_change(void *opaque, int running, RunState state)
+{
+    DumpState *s = opaque;
+
+    if (running) {
+        qmp_dump_cancel(NULL);
+        s->state = DUMP_STATE_ERROR;
+        s->error = g_strdup("vm state is changed to run\n");
+    }
+}
+
 static DumpState *dump_init(Error **errp)
 {
     CPUState *env;
@@ -514,6 +617,9 @@ static DumpState *dump_init(Error **errp)
         g_free(s->error);
         s->error = NULL;
     }
+    s->block = QLIST_FIRST(&ram_list.blocks);
+    s->start = 0;
+    s->handler = qemu_add_vm_change_state_handler(dump_vm_state_change, s);
 
     /*
      * get dump info: endian, class and architecture.
@@ -560,14 +666,24 @@ static int fd_write_vmcore(target_phys_addr_t offset, void *buf, size_t size,
 
     ret = lseek(fd, offset, SEEK_SET);
     if (ret < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            return -2;
+        }
         return -1;
     }
 
     ret = write(fd, buf, size);
-    if (ret != size) {
+    if (ret < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            return -2;
+        }
         return -1;
     }
 
+    if (ret != size) {
+        return -2;
+    }
+
     return 0;
 }
 
@@ -576,10 +692,18 @@ static void fd_cleanup(void *opaque)
     int fd = (int)(intptr_t)opaque;
 
     if (fd != -1) {
+        qemu_set_fd_handler(fd, NULL, NULL, NULL);
         close(fd);
     }
 }
 
+static int fd_dump_begin_iterate(DumpState *s, void *opaque)
+{
+    int fd = (int)(intptr_t)opaque;
+
+    return qemu_set_fd_handler(fd, NULL, dump_iterate, s);
+}
+
 static DumpState *dump_init_fd(int fd, Error **errp)
 {
     DumpState *s = dump_init(errp);
@@ -590,7 +714,9 @@ static DumpState *dump_init_fd(int fd, Error **errp)
 
     s->f = fd_write_vmcore;
     s->cleanup = fd_cleanup;
+    s->dump_begin_iterate = fd_dump_begin_iterate;
     s->opaque = (void *)(intptr_t)fd;
+    fcntl(fd, F_SETFL, O_NONBLOCK);
 
     return s;
 }
diff --git a/vl.c b/vl.c
index 1d4c350..fcc1c57 100644
--- a/vl.c
+++ b/vl.c
@@ -1248,11 +1248,12 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
 
 void vm_state_notify(int running, RunState state)
 {
-    VMChangeStateEntry *e;
+    VMChangeStateEntry *e, *next;
 
     trace_vm_state_notify(running, state);
 
-    for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
+    /* e->cb() may remove itself */
+    QLIST_FOREACH_SAFE(e, &vm_change_state_head, entries, next) {
         e->cb(e->opaque, running, state);
     }
 }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 13/14 v7] support detached dump
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (11 preceding siblings ...)
  2012-03-01  2:54 ` [Qemu-devel] [RFC][PATCH 12/14 v7] run dump at the background Wen Congyang
@ 2012-03-01  2:55 ` Wen Congyang
  2012-03-01  2:55 ` [Qemu-devel] [RFC][PATCH 14/14 v7] allow user to dump a fraction of the memory Wen Congyang
  2012-03-01  4:42 ` [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism HATAYAMA Daisuke
  14 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:55 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

Let the user to choose whether to block other monitor command while dumping.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c           |    2 +-
 hmp-commands.hx  |    9 +++++----
 hmp.c            |   49 +++++++++++++++++++++++++++++++++++++++++++++++--
 qapi-schema.json |    3 ++-
 qmp-commands.hx  |    7 +++++--
 5 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/dump.c b/dump.c
index 8224116..dd3a72c 100644
--- a/dump.c
+++ b/dump.c
@@ -721,7 +721,7 @@ static DumpState *dump_init_fd(int fd, Error **errp)
     return s;
 }
 
-void qmp_dump(const char *file, Error **errp)
+void qmp_dump(bool detach, const char *file, Error **errp)
 {
     const char *p;
     int fd = -1;
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 0c0a7b4..bd0c95d 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -883,20 +883,21 @@ ETEXI
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "file:s",
-        .params     = "file",
-        .help       = "dump to file",
+        .args_type  = "detach:-d,file:s",
+        .params     = "[-d] file",
+        .help       = "dump to file (using -d to not wait for completion)",
         .user_print = monitor_user_noop,
         .mhandler.cmd = hmp_dump,
     },
 
 
 STEXI
-@item dump @var{file}
+@item dump [-d] @var{file}
 @findex dump
 Dump to @var{file}. The file can be processed with crash or gdb.
     file: destination file(started with "file:") or destination file descriptor
           (started with "fd:")
+      -d: donot wait for completion.
 ETEXI
 #endif
 
diff --git a/hmp.c b/hmp.c
index 476d355..707701b 100644
--- a/hmp.c
+++ b/hmp.c
@@ -857,13 +857,58 @@ void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, &error);
 }
 
+typedef struct DumpingStatus
+{
+    QEMUTimer *timer;
+    Monitor *mon;
+} DumpingStatus;
+
+static void hmp_dumping_status_cb(void *opaque)
+{
+    DumpingStatus *status = opaque;
+    DumpInfo *info;
+
+    info = qmp_query_dump(NULL);
+    if (!info->has_status || strcmp(info->status, "active") == 0) {
+        qemu_mod_timer(status->timer, qemu_get_clock_ms(rt_clock) + 1000);
+    } else {
+        monitor_resume(status->mon);
+        qemu_del_timer(status->timer);
+        g_free(status);
+    }
+
+    qapi_free_DumpInfo(info);
+}
+
 void hmp_dump(Monitor *mon, const QDict *qdict)
 {
     Error *errp = NULL;
+    int detach = qdict_get_try_bool(qdict, "detach", 0);
     const char *file = qdict_get_str(qdict, "file");
 
-    qmp_dump(file, &errp);
-    hmp_handle_error(mon, &errp);
+    qmp_dump(!!detach, file, &errp);
+    if (errp) {
+        hmp_handle_error(mon, &errp);
+        return;
+    }
+
+    if (!detach) {
+        DumpingStatus *status;
+        int ret;
+
+        ret = monitor_suspend(mon);
+        if (ret < 0) {
+            monitor_printf(mon, "terminal does not allow synchronous "
+                           "migration, continuing detached\n");
+            return;
+        }
+
+        status = g_malloc0(sizeof(*status));
+        status->mon = mon;
+        status->timer = qemu_new_timer_ms(rt_clock, hmp_dumping_status_cb,
+                                          status);
+        qemu_mod_timer(status->timer, qemu_get_clock_ms(rt_clock));
+    }
 }
 
 void hmp_dump_cancel(Monitor *mon, const QDict *qdict)
diff --git a/qapi-schema.json b/qapi-schema.json
index 1e9af32..ed157d7 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1599,13 +1599,14 @@
 #
 # Dump guest's memory to vmcore.
 #
+# @detach: detached dumping.
 # @file: the filename or file descriptor of the vmcore.
 #
 # Returns: nothing on success
 #
 # Since: 1.1
 ##
-{ 'command': 'dump', 'data': { 'file': 'str' } }
+{ 'command': 'dump', 'data': { 'detach': 'bool', 'file': 'str' } }
 
 ##
 # @dump_cancel
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 666f1bc..c7b9c82 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -589,8 +589,8 @@ EQMP
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "file:s",
-        .params     = "file",
+        .args_type  = "detach:-d,file:s",
+        .params     = "[-d] file",
         .help       = "dump to file",
         .user_print = monitor_user_noop,
         .mhandler.cmd_new = qmp_marshal_input_dump,
@@ -616,6 +616,9 @@ Notes:
 
 (1) The 'info dump' command should be used to check dumping's progress
     and final result (this information is provided by the 'status' member)
+(2) All boolean arguments default to false
+(3) The user Monitor's "detach" argument is invalid in QMP and should not
+    be used
 
 EQMP
 #endif
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [Qemu-devel] [RFC][PATCH 14/14 v7] allow user to dump a fraction of the memory
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (12 preceding siblings ...)
  2012-03-01  2:55 ` [Qemu-devel] [RFC][PATCH 13/14 v7] support detached dump Wen Congyang
@ 2012-03-01  2:55 ` Wen Congyang
  2012-03-01  4:42 ` [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism HATAYAMA Daisuke
  14 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  2:55 UTC (permalink / raw)
  To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke,
	Luiz Capitulino, Eric Blake

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 dump.c           |  124 +++++++++++++++++++++++++++++++++++++++++++++++------
 hmp-commands.hx  |   14 ++++--
 hmp.c            |   13 +++++-
 memory_mapping.c |   27 ++++++++++++
 memory_mapping.h |    2 +
 qapi-schema.json |    6 ++-
 qmp-commands.hx  |    8 +++-
 7 files changed, 172 insertions(+), 22 deletions(-)

diff --git a/dump.c b/dump.c
index dd3a72c..3aa160e 100644
--- a/dump.c
+++ b/dump.c
@@ -91,6 +91,9 @@ typedef struct DumpState {
     void *opaque;
     RAMBlock *block;
     ram_addr_t start;
+    bool has_filter;
+    int64_t begin;
+    int64_t length;
     target_phys_addr_t offset;
     VMChangeStateEntry *handler;
 } DumpState;
@@ -413,17 +416,47 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
 
 /* get the memory's offset in the vmcore */
 static target_phys_addr_t get_offset(target_phys_addr_t phys_addr,
-                                     target_phys_addr_t memory_offset)
+                                     DumpState *s)
 {
     RAMBlock *block;
-    target_phys_addr_t offset = memory_offset;
+    target_phys_addr_t offset = s->memory_offset;
+    int64_t size_in_block, start;
+
+    if (s->has_filter) {
+        if (phys_addr < s->begin || phys_addr >= s->begin + s->length) {
+            return -1;
+        }
+    }
 
     QLIST_FOREACH(block, &ram_list.blocks, next) {
-        if (phys_addr >= block->offset &&
-            phys_addr < block->offset + block->length) {
-            return phys_addr - block->offset + offset;
+        if (s->has_filter) {
+            if (block->offset >= s->begin + s->length ||
+                block->offset + block->length <= s->begin) {
+                /* This block is out of the range */
+                continue;
+            }
+
+            if (s->begin <= block->offset) {
+                start = block->offset;
+            } else {
+                start = s->begin;
+            }
+
+            size_in_block = block->length - (start - block->offset);
+            if (s->begin + s->length < block->offset + block->length) {
+                size_in_block -= block->offset + block->length -
+                                 (s->begin + s->length);
+            }
+        } else {
+            start = block->offset;
+            size_in_block = block->length;
         }
-        offset += block->length;
+
+        if (phys_addr >= start && phys_addr < start + size_in_block) {
+            return phys_addr - start + offset;
+        }
+
+        offset += size_in_block;
     }
 
     return -1;
@@ -495,7 +528,7 @@ static int dump_completed(DumpState *s)
     int phdr_index = 1, ret;
 
     QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
-        offset = get_offset(memory_mapping->phys_addr, s->memory_offset);
+        offset = get_offset(memory_mapping->phys_addr, s);
         if (s->dump_info.d_class == ELFCLASS64) {
             ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
         } else {
@@ -522,6 +555,17 @@ static int get_next_block(DumpState *s, RAMBlock *block)
 
         s->start = 0;
         s->block = block;
+        if (s->has_filter) {
+            if (block->offset >= s->begin + s->length ||
+                block->offset + block->length <= s->begin) {
+                /* This block is out of the range */
+                continue;
+            }
+
+            if (s->begin > block->offset) {
+                s->start = s->begin - block->offset;
+            }
+        }
 
         return 0;
     }
@@ -600,7 +644,36 @@ static void dump_vm_state_change(void *opaque, int running, RunState state)
     }
 }
 
-static DumpState *dump_init(Error **errp)
+static ram_addr_t get_start_block(DumpState *s)
+{
+    RAMBlock *block;
+
+    if (!s->has_filter) {
+        s->block = QLIST_FIRST(&ram_list.blocks);
+        return 0;
+    }
+
+    QLIST_FOREACH(block, &ram_list.blocks, next) {
+        if (block->offset >= s->begin + s->length ||
+            block->offset + block->length <= s->begin) {
+            /* This block is out of the range */
+            continue;
+        }
+
+        s->block = block;
+        if (s->begin > block->offset ) {
+            s->start = s->begin - block->offset;
+        } else {
+            s->start = 0;
+        }
+        return s->start;
+    }
+
+    return -1;
+}
+
+static DumpState *dump_init(bool has_filter, int64_t begin, int64_t length,
+                            Error **errp)
 {
     CPUState *env;
     DumpState *s = dump_get_current();
@@ -617,8 +690,16 @@ static DumpState *dump_init(Error **errp)
         g_free(s->error);
         s->error = NULL;
     }
-    s->block = QLIST_FIRST(&ram_list.blocks);
-    s->start = 0;
+
+    s->has_filter = has_filter;
+    s->begin = begin;
+    s->length = length;
+    s->start = get_start_block(s);
+    if (s->start == -1) {
+        error_set(errp, QERR_INVALID_PARAMETER, "begin");
+        return NULL;
+    }
+
     s->handler = qemu_add_vm_change_state_handler(dump_vm_state_change, s);
 
     /*
@@ -643,6 +724,10 @@ static DumpState *dump_init(Error **errp)
     memory_mapping_list_init(&s->list);
     qemu_get_guest_memory_mapping(&s->list);
 
+    if (s->has_filter) {
+        memory_mapping_filter(&s->list, s->begin, s->length);
+    }
+
     /*
      * calculate phdr_num
      *
@@ -704,9 +789,10 @@ static int fd_dump_begin_iterate(DumpState *s, void *opaque)
     return qemu_set_fd_handler(fd, NULL, dump_iterate, s);
 }
 
-static DumpState *dump_init_fd(int fd, Error **errp)
+static DumpState *dump_init_fd(int fd, bool has_filter, int64_t begin,
+                               int64_t length, Error **errp)
 {
-    DumpState *s = dump_init(errp);
+    DumpState *s = dump_init(has_filter, begin, length, errp);
 
     if (s == NULL) {
         return NULL;
@@ -721,12 +807,22 @@ static DumpState *dump_init_fd(int fd, Error **errp)
     return s;
 }
 
-void qmp_dump(bool detach, const char *file, Error **errp)
+void qmp_dump(bool detach, const char *file, bool has_begin, int64_t begin,
+              bool has_length, int64_t length, Error **errp)
 {
     const char *p;
     int fd = -1;
     DumpState *s;
 
+    if (has_begin && !has_length) {
+        error_set(errp, QERR_MISSING_PARAMETER, "length");
+        return;
+    }
+    if (!has_begin && has_length) {
+        error_set(errp, QERR_MISSING_PARAMETER, "begin");
+        return;
+    }
+
 #if !defined(WIN32)
     if (strstart(file, "fd:", &p)) {
         fd = qemu_get_fd(p);
@@ -750,7 +846,7 @@ void qmp_dump(bool detach, const char *file, Error **errp)
         return;
     }
 
-    s = dump_init_fd(fd, errp);
+    s = dump_init_fd(fd, has_begin, begin, length, errp);
     if (!s) {
         return;
     }
diff --git a/hmp-commands.hx b/hmp-commands.hx
index bd0c95d..8b2dd38 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -883,21 +883,27 @@ ETEXI
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "detach:-d,file:s",
-        .params     = "[-d] file",
-        .help       = "dump to file (using -d to not wait for completion)",
+        .args_type  = "detach:-d,file:s,begin:i?,length:i?",
+        .params     = "[-d] file [begin] [length]",
+        .help       = "dump to file (using -d to not wait for completion)"
+                      "\n\t\t\t begin(optional): the starting physical address"
+                      "\n\t\t\t length(optional): the memory size, in bytes",
         .user_print = monitor_user_noop,
         .mhandler.cmd = hmp_dump,
     },
 
 
 STEXI
-@item dump [-d] @var{file}
+@item dump [-d] @var{file} @var{begin} @var{length}
 @findex dump
 Dump to @var{file}. The file can be processed with crash or gdb.
     file: destination file(started with "file:") or destination file descriptor
           (started with "fd:")
       -d: donot wait for completion.
+   begin: the starting physical address. It's optional, and should be specified
+          with length together.
+  length: the memory size, in bytes. It's optional, and should be specified with
+          begin together.
 ETEXI
 #endif
 
diff --git a/hmp.c b/hmp.c
index 707701b..326d277 100644
--- a/hmp.c
+++ b/hmp.c
@@ -885,8 +885,19 @@ void hmp_dump(Monitor *mon, const QDict *qdict)
     Error *errp = NULL;
     int detach = qdict_get_try_bool(qdict, "detach", 0);
     const char *file = qdict_get_str(qdict, "file");
+    bool has_begin = qdict_haskey(qdict, "begin");
+    bool has_length = qdict_haskey(qdict, "length");
+    int64_t begin = 0;
+    int64_t length = 0;
 
-    qmp_dump(!!detach, file, &errp);
+    if (has_begin) {
+        begin = qdict_get_int(qdict, "begin");
+    }
+    if (has_length) {
+        length = qdict_get_int(qdict, "length");
+    }
+
+    qmp_dump(!!detach, file, has_begin, begin, has_length, length, &errp);
     if (errp) {
         hmp_handle_error(mon, &errp);
         return;
diff --git a/memory_mapping.c b/memory_mapping.c
index 3743805..0c6ddbe 100644
--- a/memory_mapping.c
+++ b/memory_mapping.c
@@ -203,3 +203,30 @@ int qemu_get_guest_memory_mapping(MemoryMappingList *list)
 
     return 0;
 }
+
+void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
+                           int64_t length)
+{
+    MemoryMapping *cur, *next;
+
+    QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) {
+        if (cur->phys_addr >= begin + length ||
+            cur->phys_addr + cur->length <= begin) {
+            QTAILQ_REMOVE(&list->head, cur, next);
+            list->num--;
+            continue;
+        }
+
+        if (cur->phys_addr < begin) {
+            cur->length -= begin - cur->phys_addr;
+            if (cur->virt_addr) {
+                cur->virt_addr += begin - cur->phys_addr;
+            }
+            cur->phys_addr = begin;
+        }
+
+        if (cur->phys_addr + cur->length > begin + length) {
+            cur->length -= cur->phys_addr + cur->length - begin - length;
+        }
+    }
+}
diff --git a/memory_mapping.h b/memory_mapping.h
index 5760d1d..07270d5 100644
--- a/memory_mapping.h
+++ b/memory_mapping.h
@@ -49,4 +49,6 @@ void memory_mapping_list_init(MemoryMappingList *list);
  */
 int qemu_get_guest_memory_mapping(MemoryMappingList *list);
 
+void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
+                           int64_t length);
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index ed157d7..1206d51 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1601,12 +1601,16 @@
 #
 # @detach: detached dumping.
 # @file: the filename or file descriptor of the vmcore.
+# @begin: if specified, the starting physical address.
+# @length: if specified, the memory size, in bytes.
 #
 # Returns: nothing on success
 #
 # Since: 1.1
 ##
-{ 'command': 'dump', 'data': { 'detach': 'bool', 'file': 'str' } }
+{ 'command': 'dump',
+  'data': { 'detach': 'bool', 'file': 'str', '*begin': 'int',
+            '*length': 'int' } }
 
 ##
 # @dump_cancel
diff --git a/qmp-commands.hx b/qmp-commands.hx
index c7b9c82..06ff121 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -589,8 +589,8 @@ EQMP
 #if defined(CONFIG_HAVE_CORE_DUMP)
     {
         .name       = "dump",
-        .args_type  = "detach:-d,file:s",
-        .params     = "[-d] file",
+        .args_type  = "detach:-d,file:s,begin:i?,end:i?",
+        .params     = "[-d] file [begin] [length]",
         .help       = "dump to file",
         .user_print = monitor_user_noop,
         .mhandler.cmd_new = qmp_marshal_input_dump,
@@ -606,6 +606,10 @@ Arguments:
 
 - "file": destination file(started with "file:") or destination file descriptor
           (started with "fd:") (json-string)
+- "begin": the starting physical address. It's optional, and should be specified
+           with length together (json-int)
+- "length": the memory size, in bytes. It's optional, and should be specified
+            with begin together (json-int)
 
 Example:
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
  2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
                   ` (13 preceding siblings ...)
  2012-03-01  2:55 ` [Qemu-devel] [RFC][PATCH 14/14 v7] allow user to dump a fraction of the memory Wen Congyang
@ 2012-03-01  4:42 ` HATAYAMA Daisuke
  2012-03-01  5:16   ` Wen Congyang
  14 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-01  4:42 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
Date: Thu, 01 Mar 2012 10:35:44 +0800

> Hi, all
> 
> 'virsh dump' can not work when host pci device is used by guest. We have
> discussed this issue here:
> http://lists.nongnu.org/archive/html/qemu-devel/2011-10/msg00736.html
> 
> The last version is here:
> http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.html
> 
> We have determined to introduce a new command dump to dump memory. The core
> file's format can be elf.
> 
> Note:
> 1. The guest should be x86 or x86_64. The other arch is not supported now.
> 2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.

Does this say the thing caused by gdb versions with no Dwarf V3
support? If so, it's better to write that too explicitly here.

> 3. If the OS is in the second kernel, gdb may not work well, and crash can
>    work by specifying '--machdep phys_addr=xxx' in the command line. The
>    reason is that the second kernel will update the page table, and we can
>    not get the page table for the first kernel.
> 4. The cpu's state is stored in QEMU note. You neet to modify crash to use
>    it to calculate phys_base.

Again, you still need to fix crash utility to recover the 1st kernel's
first 640kB physical memory that has been reserved during switch from
1st kernel to 2nd kernel.

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
  2012-03-01  2:48 ` [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status " Wen Congyang
@ 2012-03-01  5:01   ` HATAYAMA Daisuke
  2012-03-01  5:05     ` Wen Congyang
  2012-03-01  5:10   ` HATAYAMA Daisuke
  2012-03-02  1:09   ` HATAYAMA Daisuke
  2 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-01  5:01 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

> +struct QEMUCPUState {
> +    uint32_t version;
> +    uint32_t size;
> +    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
> +    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
> +    uint64_t rip, rflags;
> +    QEMUCPUSegment cs, ds, es, fs, gs, ss;
> +    QEMUCPUSegment ldt, tr, gdt, idt;
> +    uint64_t cr[5];
> +};
> +
> +typedef struct QEMUCPUState QEMUCPUState;
<cut>
> +static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
> +{
> +    memset(s, 0, sizeof(QEMUCPUState));
> +
> +    s->version = 1;

It seems to me better to prepare a macro:

  #define QEMUCPUSTATE_VERSION (1)

and use it as:

  s->version = QEMUCPUSTATE_VERSION;

and add comment above the macro definition indicating: please count up
QEMUCPUSTATE_VERSION if you have changed definition of QEMUCPUState,
and modify the tools using this information accordingly.

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
  2012-03-01  5:01   ` HATAYAMA Daisuke
@ 2012-03-01  5:05     ` Wen Congyang
  2012-03-02  1:30       ` HATAYAMA Daisuke
  0 siblings, 1 reply; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  5:05 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/01/2012 01:01 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
> Date: Thu, 01 Mar 2012 10:48:17 +0800
> 
>> +struct QEMUCPUState {
>> +    uint32_t version;
>> +    uint32_t size;
>> +    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
>> +    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
>> +    uint64_t rip, rflags;
>> +    QEMUCPUSegment cs, ds, es, fs, gs, ss;
>> +    QEMUCPUSegment ldt, tr, gdt, idt;
>> +    uint64_t cr[5];
>> +};
>> +
>> +typedef struct QEMUCPUState QEMUCPUState;
> <cut>
>> +static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
>> +{
>> +    memset(s, 0, sizeof(QEMUCPUState));
>> +
>> +    s->version = 1;
> 
> It seems to me better to prepare a macro:
> 
>   #define QEMUCPUSTATE_VERSION (1)
> 
> and use it as:
> 
>   s->version = QEMUCPUSTATE_VERSION;
> 
> and add comment above the macro definition indicating: please count up
> QEMUCPUSTATE_VERSION if you have changed definition of QEMUCPUState,
> and modify the tools using this information accordingly.

Yes, I will fix it.

PS: Do you have any comment about QEMUCPUState? I think the content is enough
to calculate phys_base now.

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
  2012-03-01  2:48 ` [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status " Wen Congyang
  2012-03-01  5:01   ` HATAYAMA Daisuke
@ 2012-03-01  5:10   ` HATAYAMA Daisuke
  2012-03-01  5:22     ` Wen Congyang
  2012-03-02  1:09   ` HATAYAMA Daisuke
  2 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-01  5:10 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

> +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
> +                             target_phys_addr_t *offset, void *opaque)
> +{
> +    QEMUCPUState state;
> +    Elf64_Nhdr *note;
> +    char *buf;
> +    int descsz, note_size, name_size = 5;
> +    const char *name = "QEMU";
> +    int ret;
> +
> +    qemu_get_cpustate(&state, env);
> +
> +    descsz = sizeof(state);
> +    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
> +                (descsz + 3) / 4) * 4;
> +    note = g_malloc(note_size);
> +
> +    memset(note, 0, note_size);
> +    note->n_namesz = cpu_to_le32(name_size);
> +    note->n_descsz = cpu_to_le32(descsz);
> +    note->n_type = 0;
> +    buf = (char *)note;
> +    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
> +    memcpy(buf, name, name_size);
> +    buf += ((name_size + 3) / 4) * 4;
> +    memcpy(buf, &state, sizeof(state));

x86_64_write_elf64_note() and x86_write_elf64_note() does the same
processing for note data. Is it better to do this in helper functions
in common?

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
  2012-03-01  4:42 ` [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism HATAYAMA Daisuke
@ 2012-03-01  5:16   ` Wen Congyang
  2012-03-02  0:49     ` HATAYAMA Daisuke
  0 siblings, 1 reply; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  5:16 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/01/2012 12:42 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
> Date: Thu, 01 Mar 2012 10:35:44 +0800
> 
>> Hi, all
>>
>> 'virsh dump' can not work when host pci device is used by guest. We have
>> discussed this issue here:
>> http://lists.nongnu.org/archive/html/qemu-devel/2011-10/msg00736.html
>>
>> The last version is here:
>> http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.html
>>
>> We have determined to introduce a new command dump to dump memory. The core
>> file's format can be elf.
>>
>> Note:
>> 1. The guest should be x86 or x86_64. The other arch is not supported now.
>> 2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.
> 
> Does this say the thing caused by gdb versions with no Dwarf V3
> support? If so, it's better to write that too explicitly here.

I donot know why gdb crashed, and I cannot reproduce this problem now.

> 
>> 3. If the OS is in the second kernel, gdb may not work well, and crash can
>>    work by specifying '--machdep phys_addr=xxx' in the command line. The
>>    reason is that the second kernel will update the page table, and we can
>>    not get the page table for the first kernel.
>> 4. The cpu's state is stored in QEMU note. You neet to modify crash to use
>>    it to calculate phys_base.
> 
> Again, you still need to fix crash utility to recover the 1st kernel's
> first 640kB physical memory that has been reserved during switch from
> 1st kernel to 2nd kernel.

It is another work, I will try to do it in the future.

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
  2012-03-01  5:10   ` HATAYAMA Daisuke
@ 2012-03-01  5:22     ` Wen Congyang
  0 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  5:22 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/01/2012 01:10 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
> Date: Thu, 01 Mar 2012 10:48:17 +0800
> 
>> +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
>> +                             target_phys_addr_t *offset, void *opaque)
>> +{
>> +    QEMUCPUState state;
>> +    Elf64_Nhdr *note;
>> +    char *buf;
>> +    int descsz, note_size, name_size = 5;
>> +    const char *name = "QEMU";
>> +    int ret;
>> +
>> +    qemu_get_cpustate(&state, env);
>> +
>> +    descsz = sizeof(state);
>> +    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
>> +                (descsz + 3) / 4) * 4;
>> +    note = g_malloc(note_size);
>> +
>> +    memset(note, 0, note_size);
>> +    note->n_namesz = cpu_to_le32(name_size);
>> +    note->n_descsz = cpu_to_le32(descsz);
>> +    note->n_type = 0;
>> +    buf = (char *)note;
>> +    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
>> +    memcpy(buf, name, name_size);
>> +    buf += ((name_size + 3) / 4) * 4;
>> +    memcpy(buf, &state, sizeof(state));
> 
> x86_64_write_elf64_note() and x86_write_elf64_note() does the same
> processing for note data. Is it better to do this in helper functions
> in common?

I forgot to merge them. I will fix it.

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping
  2012-03-01  2:43 ` [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping Wen Congyang
@ 2012-03-01  6:01   ` HATAYAMA Daisuke
  2012-03-01  6:17     ` Wen Congyang
  0 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-01  6:01 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 04/14 v7] Add API to get memory mapping
Date: Thu, 01 Mar 2012 10:43:13 +0800

> +int qemu_get_guest_memory_mapping(MemoryMappingList *list)
> +{
> +    CPUState *env;
> +    MemoryMapping *memory_mapping;
> +    RAMBlock *block;
> +    ram_addr_t offset, length;
> +    int ret;
> +
> +#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
> +        ret = cpu_get_memory_mapping(list, env);
> +        if (ret < 0) {
> +            return -1;
> +        }
> +    }
> +#else
> +    return -2;
> +#endif
> +
> +    /* some memory may be not mapped, add them into memory mapping's list */

The part from here is logic fully for 2nd kernel? If so, I think it
better to describe why this addtional mapping is needed; we should
assume most people doesn't know kdump mechanism.

> +    QLIST_FOREACH(block, &ram_list.blocks, next) {
> +        offset = block->offset;
> +        length = block->length;
> +
> +        QTAILQ_FOREACH(memory_mapping, &list->head, next) {
> +            if (memory_mapping->phys_addr >= (offset + length)) {
> +                /*
> +                 * memory_mapping's list does not conatin the region
> +                 * [offset, offset+length)
> +                 */
> +                create_new_memory_mapping(list, offset, 0, length);
> +                length = 0;
> +                break;
> +            }
> +
> +            if ((memory_mapping->phys_addr + memory_mapping->length) <=
> +                offset) {
> +                continue;
> +            }
> +
> +            if (memory_mapping->phys_addr > offset) {
> +                /*
> +                 * memory_mapping's list does not conatin the region
> +                 * [offset, memory_mapping->phys_addr)
> +                 */
> +                create_new_memory_mapping(list, offset, 0,
> +                                          memory_mapping->phys_addr - offset);
> +            }
> +
> +            if ((offset + length) <=
> +                (memory_mapping->phys_addr + memory_mapping->length)) {
> +                length = 0;
> +                break;
> +            }
> +            length -= memory_mapping->phys_addr + memory_mapping->length -
> +                      offset;
> +            offset = memory_mapping->phys_addr + memory_mapping->length;
> +        }
> +
> +        if (length > 0) {
> +            /*
> +             * memory_mapping's list does not conatin the region
> +             * [offset, memory_mapping->phys_addr)
> +             */
> +            create_new_memory_mapping(list, offset, 0, length);
> +        }
> +    }
> +
> +    return 0;
> +}

I think it more readable if shortening memory_mapping->phys_addr and
memmory_maping->length at the berinning of the innermost foreach loop.

  m_phys_addr = memory_mapping->phys_addr;
  m_length = memory_mapping->length;

Then, each conditionals becomes compact.

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
  2012-03-01  2:41 ` [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping() Wen Congyang
@ 2012-03-01  6:13   ` HATAYAMA Daisuke
  2012-03-01  6:21     ` Wen Congyang
  0 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-01  6:13 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
Date: Thu, 01 Mar 2012 10:41:47 +0800

> +int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
> +{
> +    if (env->cr[4] & CR4_PAE_MASK) {
> +#ifdef TARGET_X86_64
> +        if (env->hflags & HF_LMA_MASK) {
> +            target_phys_addr_t pml4e_addr;
> +
> +            pml4e_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
> +            walk_pml4e(list, pml4e_addr, env->a20_mask);
> +        } else
> +#endif
> +        {
> +            target_phys_addr_t pdpe_addr;
> +
> +            pdpe_addr = (env->cr[3] & ~0x1f) & env->a20_mask;
> +            walk_pdpe2(list, pdpe_addr, env->a20_mask);
> +        }
> +    } else {
> +        target_phys_addr_t pde_addr;
> +        bool pse;
> +
> +        pde_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
> +        pse = !!(env->cr[4] & CR4_PSE_MASK);
> +        walk_pde2(list, pde_addr, env->a20_mask, pse);
> +    }
> +
> +    return 0;
> +}

Does this assume paging mode? I don't know qemu very well, but qemu
dump command runs externally to guest machine, so I think the machine
could be in the state with paging disabled where CR4 doesn't refer to
page table as expected.

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping
  2012-03-01  6:01   ` HATAYAMA Daisuke
@ 2012-03-01  6:17     ` Wen Congyang
  2012-03-01  7:11       ` HATAYAMA Daisuke
  0 siblings, 1 reply; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  6:17 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/01/2012 02:01 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 04/14 v7] Add API to get memory mapping
> Date: Thu, 01 Mar 2012 10:43:13 +0800
> 
>> +int qemu_get_guest_memory_mapping(MemoryMappingList *list)
>> +{
>> +    CPUState *env;
>> +    MemoryMapping *memory_mapping;
>> +    RAMBlock *block;
>> +    ram_addr_t offset, length;
>> +    int ret;
>> +
>> +#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
>> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
>> +        ret = cpu_get_memory_mapping(list, env);
>> +        if (ret < 0) {
>> +            return -1;
>> +        }
>> +    }
>> +#else
>> +    return -2;
>> +#endif
>> +
>> +    /* some memory may be not mapped, add them into memory mapping's list */
> 
> The part from here is logic fully for 2nd kernel? If so, I think it
> better to describe why this addtional mapping is needed; we should
> assume most people doesn't know kdump mechanism.

Not only for 2nd kernel. If the guest has 1 vcpu, and is in the 2nd kernel,
we need this logic for 1st kernel.

Thanks
Wen Congyang

> 
>> +    QLIST_FOREACH(block, &ram_list.blocks, next) {
>> +        offset = block->offset;
>> +        length = block->length;
>> +
>> +        QTAILQ_FOREACH(memory_mapping, &list->head, next) {
>> +            if (memory_mapping->phys_addr >= (offset + length)) {
>> +                /*
>> +                 * memory_mapping's list does not conatin the region
>> +                 * [offset, offset+length)
>> +                 */
>> +                create_new_memory_mapping(list, offset, 0, length);
>> +                length = 0;
>> +                break;
>> +            }
>> +
>> +            if ((memory_mapping->phys_addr + memory_mapping->length) <=
>> +                offset) {
>> +                continue;
>> +            }
>> +
>> +            if (memory_mapping->phys_addr > offset) {
>> +                /*
>> +                 * memory_mapping's list does not conatin the region
>> +                 * [offset, memory_mapping->phys_addr)
>> +                 */
>> +                create_new_memory_mapping(list, offset, 0,
>> +                                          memory_mapping->phys_addr - offset);
>> +            }
>> +
>> +            if ((offset + length) <=
>> +                (memory_mapping->phys_addr + memory_mapping->length)) {
>> +                length = 0;
>> +                break;
>> +            }
>> +            length -= memory_mapping->phys_addr + memory_mapping->length -
>> +                      offset;
>> +            offset = memory_mapping->phys_addr + memory_mapping->length;
>> +        }
>> +
>> +        if (length > 0) {
>> +            /*
>> +             * memory_mapping's list does not conatin the region
>> +             * [offset, memory_mapping->phys_addr)
>> +             */
>> +            create_new_memory_mapping(list, offset, 0, length);
>> +        }
>> +    }
>> +
>> +    return 0;
>> +}
> 
> I think it more readable if shortening memory_mapping->phys_addr and
> memmory_maping->length at the berinning of the innermost foreach loop.
> 
>   m_phys_addr = memory_mapping->phys_addr;
>   m_length = memory_mapping->length;
> 
> Then, each conditionals becomes compact.
> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
  2012-03-01  6:13   ` HATAYAMA Daisuke
@ 2012-03-01  6:21     ` Wen Congyang
  2012-03-02  2:16       ` HATAYAMA Daisuke
  0 siblings, 1 reply; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  6:21 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/01/2012 02:13 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
> Date: Thu, 01 Mar 2012 10:41:47 +0800
> 
>> +int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
>> +{
>> +    if (env->cr[4] & CR4_PAE_MASK) {
>> +#ifdef TARGET_X86_64
>> +        if (env->hflags & HF_LMA_MASK) {
>> +            target_phys_addr_t pml4e_addr;
>> +
>> +            pml4e_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
>> +            walk_pml4e(list, pml4e_addr, env->a20_mask);
>> +        } else
>> +#endif
>> +        {
>> +            target_phys_addr_t pdpe_addr;
>> +
>> +            pdpe_addr = (env->cr[3] & ~0x1f) & env->a20_mask;
>> +            walk_pdpe2(list, pdpe_addr, env->a20_mask);
>> +        }
>> +    } else {
>> +        target_phys_addr_t pde_addr;
>> +        bool pse;
>> +
>> +        pde_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
>> +        pse = !!(env->cr[4] & CR4_PSE_MASK);
>> +        walk_pde2(list, pde_addr, env->a20_mask, pse);
>> +    }
>> +
>> +    return 0;
>> +}
> 
> Does this assume paging mode? I don't know qemu very well, but qemu
> dump command runs externally to guest machine, so I think the machine
> could be in the state with paging disabled where CR4 doesn't refer to
> page table as expected.

CR4? I think you want to say CR3.

Yes, the guest may be in the state without paging mode. I will fix it.

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory
  2012-03-01  2:51 ` [Qemu-devel] [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
@ 2012-03-01  7:04   ` HATAYAMA Daisuke
  2012-03-01  7:21     ` Wen Congyang
  0 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-01  7:04 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory
Date: Thu, 01 Mar 2012 10:51:42 +0800

> +    /*
> +     * calculate phdr_num
> +     *
> +     * the type of phdr->num is uint16_t, so we should avoid overflow
> +     */
> +    s->phdr_num = 1; /* PT_NOTE */
> +    if (s->list.num > (1 << 16) - 2) {
> +        s->phdr_num = (1 << 16) - 1;
> +    } else {
> +        s->phdr_num += s->list.num;
> +    }
> +
> +    return s;
> +}

Though e_phnum is uint16_t at default, there's extension up to
uint32_t. Look at relatively new manual page. This is from FC14's.

     e_phnum     This member  holds the number of  entries in the
                 program  header  table.   Thus  the  product  of
                 e_phentsize and  e_phnum gives the  table's size
                 in  bytes.  If  a  file has  no program  header,
                 e_phnum holds the value zero.

                 If the  number of entries in  the program header
                 table  is  larger   than  or  equal  to  PN_XNUM
                 (0xffff), this member holds PN_XNUM (0xffff) and
                 the real number of entries in the program header
                 table  is  held in  the  sh_info  member of  the
                 initial   entry   in   section   header   table.
                 Otherwise,  the sh_info  member  of the  initial
                 entry contains the value zero.

                 PN_XNUM  This is defined  as 0xffff, the largest
                          number  e_phnum  can  have,  specifying
                          where  the  actual  number  of  program
                          headers is assigned.

Recent kernel, gdb and tools in binutils supports this. But crash
doesn't, so you need to fix this.

I'm interested in the number of program headers at worst
case. According to Intel Programming Guide 3A, Table 4-1. shows
physical-address width on IA-32e is up to 52 and linear-address width
is 48. Can the number exceed this limit in theory? Also how many
program headers are created typically?

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping
  2012-03-01  6:17     ` Wen Congyang
@ 2012-03-01  7:11       ` HATAYAMA Daisuke
  2012-03-01  7:22         ` Wen Congyang
  0 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-01  7:11 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: Re: [RFC][PATCH 04/14 v7] Add API to get memory mapping
Date: Thu, 01 Mar 2012 14:17:53 +0800

> At 03/01/2012 02:01 PM, HATAYAMA Daisuke Wrote:
>> From: Wen Congyang <wency@cn.fujitsu.com>
>> Subject: [RFC][PATCH 04/14 v7] Add API to get memory mapping
>> Date: Thu, 01 Mar 2012 10:43:13 +0800
>> 
>>> +int qemu_get_guest_memory_mapping(MemoryMappingList *list)
>>> +{
>>> +    CPUState *env;
>>> +    MemoryMapping *memory_mapping;
>>> +    RAMBlock *block;
>>> +    ram_addr_t offset, length;
>>> +    int ret;
>>> +
>>> +#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
>>> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
>>> +        ret = cpu_get_memory_mapping(list, env);
>>> +        if (ret < 0) {
>>> +            return -1;
>>> +        }
>>> +    }
>>> +#else
>>> +    return -2;
>>> +#endif
>>> +
>>> +    /* some memory may be not mapped, add them into memory mapping's list */
>> 
>> The part from here is logic fully for 2nd kernel? If so, I think it
>> better to describe why this addtional mapping is needed; we should
>> assume most people doesn't know kdump mechanism.
> 
> Not only for 2nd kernel. If the guest has 1 vcpu, and is in the 2nd kernel,
> we need this logic for 1st kernel.
> 

So you should describe two cases explicitly. I don't understand them
from ``some memory''.

and please consider cleanup below too. Conditionals over two lines are
hard to read.

>> 
>> I think it more readable if shortening memory_mapping->phys_addr and
>> memmory_maping->length at the berinning of the innermost foreach loop.
>> 
>>   m_phys_addr = memory_mapping->phys_addr;
>>   m_length = memory_mapping->length;
>> 
>> Then, each conditionals becomes compact.

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory
  2012-03-01  7:04   ` HATAYAMA Daisuke
@ 2012-03-01  7:21     ` Wen Congyang
  0 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  7:21 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/01/2012 03:04 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory
> Date: Thu, 01 Mar 2012 10:51:42 +0800
> 
>> +    /*
>> +     * calculate phdr_num
>> +     *
>> +     * the type of phdr->num is uint16_t, so we should avoid overflow
>> +     */
>> +    s->phdr_num = 1; /* PT_NOTE */
>> +    if (s->list.num > (1 << 16) - 2) {
>> +        s->phdr_num = (1 << 16) - 1;
>> +    } else {
>> +        s->phdr_num += s->list.num;
>> +    }
>> +
>> +    return s;
>> +}
> 
> Though e_phnum is uint16_t at default, there's extension up to
> uint32_t. Look at relatively new manual page. This is from FC14's.
> 
>      e_phnum     This member  holds the number of  entries in the
>                  program  header  table.   Thus  the  product  of
>                  e_phentsize and  e_phnum gives the  table's size
>                  in  bytes.  If  a  file has  no program  header,
>                  e_phnum holds the value zero.
> 
>                  If the  number of entries in  the program header
>                  table  is  larger   than  or  equal  to  PN_XNUM
>                  (0xffff), this member holds PN_XNUM (0xffff) and
>                  the real number of entries in the program header
>                  table  is  held in  the  sh_info  member of  the
>                  initial   entry   in   section   header   table.
>                  Otherwise,  the sh_info  member  of the  initial
>                  entry contains the value zero.
> 
>                  PN_XNUM  This is defined  as 0xffff, the largest
>                           number  e_phnum  can  have,  specifying
>                           where  the  actual  number  of  program
>                           headers is assigned.

Good news.

> 
> Recent kernel, gdb and tools in binutils supports this. But crash
> doesn't, so you need to fix this.

I think it can be easily fixed.

> 
> I'm interested in the number of program headers at worst
> case. According to Intel Programming Guide 3A, Table 4-1. shows
> physical-address width on IA-32e is up to 52 and linear-address width
> is 48. Can the number exceed this limit in theory? Also how many
> program headers are created typically?

In my test, the guest has 512M memory, and it contains about 1000~2000 program
headers.

In theory, if the guest has 2^52 memory, the number can still exceed this limit.
Tha maxnium number is 2^52/2^12

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping
  2012-03-01  7:11       ` HATAYAMA Daisuke
@ 2012-03-01  7:22         ` Wen Congyang
  0 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  7:22 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/01/2012 03:11 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: Re: [RFC][PATCH 04/14 v7] Add API to get memory mapping
> Date: Thu, 01 Mar 2012 14:17:53 +0800
> 
>> At 03/01/2012 02:01 PM, HATAYAMA Daisuke Wrote:
>>> From: Wen Congyang <wency@cn.fujitsu.com>
>>> Subject: [RFC][PATCH 04/14 v7] Add API to get memory mapping
>>> Date: Thu, 01 Mar 2012 10:43:13 +0800
>>>
>>>> +int qemu_get_guest_memory_mapping(MemoryMappingList *list)
>>>> +{
>>>> +    CPUState *env;
>>>> +    MemoryMapping *memory_mapping;
>>>> +    RAMBlock *block;
>>>> +    ram_addr_t offset, length;
>>>> +    int ret;
>>>> +
>>>> +#if defined(CONFIG_HAVE_GET_MEMORY_MAPPING)
>>>> +    for (env = first_cpu; env != NULL; env = env->next_cpu) {
>>>> +        ret = cpu_get_memory_mapping(list, env);
>>>> +        if (ret < 0) {
>>>> +            return -1;
>>>> +        }
>>>> +    }
>>>> +#else
>>>> +    return -2;
>>>> +#endif
>>>> +
>>>> +    /* some memory may be not mapped, add them into memory mapping's list */
>>>
>>> The part from here is logic fully for 2nd kernel? If so, I think it
>>> better to describe why this addtional mapping is needed; we should
>>> assume most people doesn't know kdump mechanism.
>>
>> Not only for 2nd kernel. If the guest has 1 vcpu, and is in the 2nd kernel,
>> we need this logic for 1st kernel.
>>
> 
> So you should describe two cases explicitly. I don't understand them
> from ``some memory''.
> 
> and please consider cleanup below too. Conditionals over two lines are
> hard to read.

OK. I will fix it.

Thanks
Wen Congyang

> 
>>>
>>> I think it more readable if shortening memory_mapping->phys_addr and
>>> memmory_maping->length at the berinning of the innermost foreach loop.
>>>
>>>   m_phys_addr = memory_mapping->phys_addr;
>>>   m_length = memory_mapping->length;
>>>
>>> Then, each conditionals becomes compact.
> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list
  2012-03-01  2:39 ` [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list Wen Congyang
@ 2012-03-01  8:33   ` HATAYAMA Daisuke
  2012-03-01  8:58     ` Wen Congyang
  0 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-01  8:33 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 01/14 v7] Add API to create memory mapping list
Date: Thu, 01 Mar 2012 10:39:35 +0800

> +static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
> +                                                   MemoryMapping *mapping)

> +void memory_mapping_list_add_sorted(MemoryMappingList *list,

These functions not only sort but also merge elements of mapping
list. Is there another name that represents what these are doing more
properly?

> +                                    target_phys_addr_t phys_addr,
> +                                    target_phys_addr_t virt_addr,
> +                                    ram_addr_t length)
> +{
> +    MemoryMapping *memory_mapping, *last_mapping;
> +
> +    if (QTAILQ_EMPTY(&list->head)) {
> +        create_new_memory_mapping(list, phys_addr, virt_addr, length);
> +        return;
> +    }
> +
> +    last_mapping = list->last_mapping;
> +    if (last_mapping) {
> +        if ((phys_addr == (last_mapping->phys_addr + last_mapping->length)) &&
> +            (virt_addr == (last_mapping->virt_addr + last_mapping->length))) {
> +            last_mapping->length += length;
> +            return;
> +        }
> +    }
> +
> +    QTAILQ_FOREACH(memory_mapping, &list->head, next) {
> +        last_mapping = memory_mapping;
> +        if ((phys_addr == (last_mapping->phys_addr + last_mapping->length)) &&
> +            (virt_addr == (last_mapping->virt_addr + last_mapping->length))) {
> +            last_mapping->length += length;
> +            list->last_mapping = last_mapping;
> +            return;
> +        }

Please don't use a single variable in multiple meanings in the same
function. It appears to me that the variable last_mapping is used as
n-th entry connected to the list->head within this for loop. So
this_mapping, for example, is reasonable rather than last_mapping. All
use of last_mapping within the for loop can be replaced with
memory_mapping, right?

> +
> +        if (phys_addr + length < last_mapping->phys_addr) {
> +            /* create a new region before last_mapping */
> +            break;
> +        }
> +
> +        if (phys_addr >= (last_mapping->phys_addr + last_mapping->length)) {
> +            /* last_mapping does not contain this region */
> +            continue;
> +        }
> +
> +        if ((virt_addr - last_mapping->virt_addr) !=
> +            (phys_addr - last_mapping->phys_addr)) {
> +            /*
> +             * last_mapping contains this region, but we cannot merge this
> +             * region into last_mapping. Try the next memory mapping.
> +             */
> +            continue;
> +        }

Does this condition means the current mapping and the last mapping are
contiguous both phisically and viurtually? If so, it's better to write
the condition so readers can understand that more easily.

> +
> +        /* merge this region into last_mapping */
> +        if (virt_addr < last_mapping->virt_addr) {
> +            last_mapping->length += last_mapping->virt_addr - virt_addr;
> +            last_mapping->virt_addr = virt_addr;
> +        }
> +
> +        if ((virt_addr + length) >
> +            (last_mapping->virt_addr + last_mapping->length)) {
> +            last_mapping->length = virt_addr + length - last_mapping->virt_addr;
> +        }
> +
> +        list->last_mapping = last_mapping;
> +        return;
> +    }
> +
> +    /* this region can not be merged into any existed memory mapping. */
> +    create_new_memory_mapping(list, phys_addr, virt_addr, length);
> +}

How about adding helper functions for expressing each conditionals?
Just like below. Then I think the code gets more readable.

  bool mapping_proper_succeor(MemoryMapping *map,
                              target_phys_addr_t phys_addr,
                              target_virt_addr_t virt_addr);
  bool mapping_physically_contains(MemoryMapping *map,
                        target_phys_addr_t phys_addr);
  bool mapping_physically_virtually_contiguous(MemoryMapping *map,
                                               target_phys_addr_t phys_addr,
                                               target_virt_addr_t virt_addr);
  void mapping_merge(MemoryMapping *map, target_phys_addr_t phys_addr,
                     target_virt_addr_t virt_addr);

I'm not confident of the naming, these are example, and assuming
define all as static inline functions.

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list
  2012-03-01  8:33   ` HATAYAMA Daisuke
@ 2012-03-01  8:58     ` Wen Congyang
  0 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-01  8:58 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/01/2012 04:33 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 01/14 v7] Add API to create memory mapping list
> Date: Thu, 01 Mar 2012 10:39:35 +0800
> 
>> +static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
>> +                                                   MemoryMapping *mapping)
> 
>> +void memory_mapping_list_add_sorted(MemoryMappingList *list,
> 
> These functions not only sort but also merge elements of mapping
> list. Is there another name that represents what these are doing more
> properly?
> 
>> +                                    target_phys_addr_t phys_addr,
>> +                                    target_phys_addr_t virt_addr,
>> +                                    ram_addr_t length)
>> +{
>> +    MemoryMapping *memory_mapping, *last_mapping;
>> +
>> +    if (QTAILQ_EMPTY(&list->head)) {
>> +        create_new_memory_mapping(list, phys_addr, virt_addr, length);
>> +        return;
>> +    }
>> +
>> +    last_mapping = list->last_mapping;
>> +    if (last_mapping) {
>> +        if ((phys_addr == (last_mapping->phys_addr + last_mapping->length)) &&
>> +            (virt_addr == (last_mapping->virt_addr + last_mapping->length))) {
>> +            last_mapping->length += length;
>> +            return;
>> +        }
>> +    }
>> +
>> +    QTAILQ_FOREACH(memory_mapping, &list->head, next) {
>> +        last_mapping = memory_mapping;
>> +        if ((phys_addr == (last_mapping->phys_addr + last_mapping->length)) &&
>> +            (virt_addr == (last_mapping->virt_addr + last_mapping->length))) {
>> +            last_mapping->length += length;
>> +            list->last_mapping = last_mapping;
>> +            return;
>> +        }
> 
> Please don't use a single variable in multiple meanings in the same
> function. It appears to me that the variable last_mapping is used as
> n-th entry connected to the list->head within this for loop. So
> this_mapping, for example, is reasonable rather than last_mapping. All
> use of last_mapping within the for loop can be replaced with
> memory_mapping, right?

OK

> 
>> +
>> +        if (phys_addr + length < last_mapping->phys_addr) {
>> +            /* create a new region before last_mapping */
>> +            break;
>> +        }
>> +
>> +        if (phys_addr >= (last_mapping->phys_addr + last_mapping->length)) {
>> +            /* last_mapping does not contain this region */
>> +            continue;
>> +        }
>> +
>> +        if ((virt_addr - last_mapping->virt_addr) !=
>> +            (phys_addr - last_mapping->phys_addr)) {
>> +            /*
>> +             * last_mapping contains this region, but we cannot merge this
>> +             * region into last_mapping. Try the next memory mapping.
>> +             */
>> +            continue;
>> +        }
> 
> Does this condition means the current mapping and the last mapping are
> contiguous both phisically and viurtually? If so, it's better to write
> the condition so readers can understand that more easily.

current mapping and last mapping are always contiguous both phisically and
virtually.

> 
>> +
>> +        /* merge this region into last_mapping */
>> +        if (virt_addr < last_mapping->virt_addr) {
>> +            last_mapping->length += last_mapping->virt_addr - virt_addr;
>> +            last_mapping->virt_addr = virt_addr;
>> +        }
>> +
>> +        if ((virt_addr + length) >
>> +            (last_mapping->virt_addr + last_mapping->length)) {
>> +            last_mapping->length = virt_addr + length - last_mapping->virt_addr;
>> +        }
>> +
>> +        list->last_mapping = last_mapping;
>> +        return;
>> +    }
>> +
>> +    /* this region can not be merged into any existed memory mapping. */
>> +    create_new_memory_mapping(list, phys_addr, virt_addr, length);
>> +}
> 
> How about adding helper functions for expressing each conditionals?
> Just like below. Then I think the code gets more readable.
> 
>   bool mapping_proper_succeor(MemoryMapping *map,
>                               target_phys_addr_t phys_addr,
>                               target_virt_addr_t virt_addr);
>   bool mapping_physically_contains(MemoryMapping *map,
>                         target_phys_addr_t phys_addr);
>   bool mapping_physically_virtually_contiguous(MemoryMapping *map,
>                                                target_phys_addr_t phys_addr,
>                                                target_virt_addr_t virt_addr);
>   void mapping_merge(MemoryMapping *map, target_phys_addr_t phys_addr,
>                      target_virt_addr_t virt_addr);
> 
> I'm not confident of the naming, these are example, and assuming
> define all as static inline functions.

Hmm, I think this inline functions make the code more readable. So I will
modify my code.

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
  2012-03-01  5:16   ` Wen Congyang
@ 2012-03-02  0:49     ` HATAYAMA Daisuke
  2012-03-02  1:39       ` Wen Congyang
  0 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-02  0:49 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: Re: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
Date: Thu, 01 Mar 2012 13:16:47 +0800

> At 03/01/2012 12:42 PM, HATAYAMA Daisuke Wrote:
>> From: Wen Congyang <wency@cn.fujitsu.com>
>> Subject: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
>> Date: Thu, 01 Mar 2012 10:35:44 +0800
>> 
>>> Hi, all
>>>
>>> 'virsh dump' can not work when host pci device is used by guest. We have
>>> discussed this issue here:
>>> http://lists.nongnu.org/archive/html/qemu-devel/2011-10/msg00736.html
>>>
>>> The last version is here:
>>> http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.html
>>>
>>> We have determined to introduce a new command dump to dump memory. The core
>>> file's format can be elf.
>>>
>>> Note:
>>> 1. The guest should be x86 or x86_64. The other arch is not supported now.
>>> 2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.
>> 
>> Does this say the thing caused by gdb versions with no Dwarf V3
>> support? If so, it's better to write that too explicitly here.
> 
> I donot know why gdb crashed, and I cannot reproduce this problem now.
> 

Sorry. I meant Dwarf4. Recent GCC emits binary with Dwarf4 in default,
and older GDBs cannot handle them although I don't know this is the
same as what you saw.

>>> 3. If the OS is in the second kernel, gdb may not work well, and crash can
>>>    work by specifying '--machdep phys_addr=xxx' in the command line. The
>>>    reason is that the second kernel will update the page table, and we can
>>>    not get the page table for the first kernel.
>>> 4. The cpu's state is stored in QEMU note. You neet to modify crash to use
>>>    it to calculate phys_base.
>> 
>> Again, you still need to fix crash utility to recover the 1st kernel's
>> first 640kB physical memory that has been reserved during switch from
>> 1st kernel to 2nd kernel.
> 
> It is another work, I will try to do it in the future.
> 

Please.

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
  2012-03-01  2:48 ` [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status " Wen Congyang
  2012-03-01  5:01   ` HATAYAMA Daisuke
  2012-03-01  5:10   ` HATAYAMA Daisuke
@ 2012-03-02  1:09   ` HATAYAMA Daisuke
  2012-03-02  1:42     ` Wen Congyang
  2 siblings, 1 reply; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-02  1:09 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

> +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
> +                             target_phys_addr_t *offset, void *opaque)
> +{
> +    QEMUCPUState state;
> +    Elf64_Nhdr *note;

<cut>

> +    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +

                            ELF64_Nhdr?

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
  2012-03-01  5:05     ` Wen Congyang
@ 2012-03-02  1:30       ` HATAYAMA Daisuke
  0 siblings, 0 replies; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-02  1:30 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: Re: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 13:05:31 +0800

> At 03/01/2012 01:01 PM, HATAYAMA Daisuke Wrote:
>> From: Wen Congyang <wency@cn.fujitsu.com>
>> Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
>> Date: Thu, 01 Mar 2012 10:48:17 +0800
>> 
>>> +struct QEMUCPUState {
>>> +    uint32_t version;
>>> +    uint32_t size;
>>> +    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
>>> +    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
>>> +    uint64_t rip, rflags;
>>> +    QEMUCPUSegment cs, ds, es, fs, gs, ss;
>>> +    QEMUCPUSegment ldt, tr, gdt, idt;
>>> +    uint64_t cr[5];
>>> +};
>>> +
>>> +typedef struct QEMUCPUState QEMUCPUState;
>> <cut>
>>> +static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
>>> +{
>>> +    memset(s, 0, sizeof(QEMUCPUState));
>>> +
>>> +    s->version = 1;
>> 
>> It seems to me better to prepare a macro:
>> 
>>   #define QEMUCPUSTATE_VERSION (1)
>> 
>> and use it as:
>> 
>>   s->version = QEMUCPUSTATE_VERSION;
>> 
>> and add comment above the macro definition indicating: please count up
>> QEMUCPUSTATE_VERSION if you have changed definition of QEMUCPUState,
>> and modify the tools using this information accordingly.
> 
> Yes, I will fix it.
> 
> PS: Do you have any comment about QEMUCPUState? I think the content is enough
> to calculate phys_base now.
> 

Yes, for the purpose it might be enough. But looking at CPUX86State,
there are still useful states for debugging to know guest machine
state at crash, such as device states, NMI states, TSC, etc.

For now, I think it's OK to pick up minimum kinds of registers
only. If they are classified sufficiently in their types such as
general registers, floating-point registers, control registers,
processor features and so on, it's possible to add new note later
easily.

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
  2012-03-02  0:49     ` HATAYAMA Daisuke
@ 2012-03-02  1:39       ` Wen Congyang
  0 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-02  1:39 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/02/2012 08:49 AM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: Re: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
> Date: Thu, 01 Mar 2012 13:16:47 +0800
> 
>> At 03/01/2012 12:42 PM, HATAYAMA Daisuke Wrote:
>>> From: Wen Congyang <wency@cn.fujitsu.com>
>>> Subject: [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism
>>> Date: Thu, 01 Mar 2012 10:35:44 +0800
>>>
>>>> Hi, all
>>>>
>>>> 'virsh dump' can not work when host pci device is used by guest. We have
>>>> discussed this issue here:
>>>> http://lists.nongnu.org/archive/html/qemu-devel/2011-10/msg00736.html
>>>>
>>>> The last version is here:
>>>> http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg01007.html
>>>>
>>>> We have determined to introduce a new command dump to dump memory. The core
>>>> file's format can be elf.
>>>>
>>>> Note:
>>>> 1. The guest should be x86 or x86_64. The other arch is not supported now.
>>>> 2. If you use old gdb, gdb may crash. I use gdb-7.3.1, and it does not crash.
>>>
>>> Does this say the thing caused by gdb versions with no Dwarf V3
>>> support? If so, it's better to write that too explicitly here.
>>
>> I donot know why gdb crashed, and I cannot reproduce this problem now.
>>
> 
> Sorry. I meant Dwarf4. Recent GCC emits binary with Dwarf4 in default,
> and older GDBs cannot handle them although I don't know this is the
> same as what you saw.

I guess it is not, as I cannot reproduce this problem.

Thanks
Wen Congyang

> 
>>>> 3. If the OS is in the second kernel, gdb may not work well, and crash can
>>>>    work by specifying '--machdep phys_addr=xxx' in the command line. The
>>>>    reason is that the second kernel will update the page table, and we can
>>>>    not get the page table for the first kernel.
>>>> 4. The cpu's state is stored in QEMU note. You neet to modify crash to use
>>>>    it to calculate phys_base.
>>>
>>> Again, you still need to fix crash utility to recover the 1st kernel's
>>> first 640kB physical memory that has been reserved during switch from
>>> 1st kernel to 2nd kernel.
>>
>> It is another work, I will try to do it in the future.
>>
> 
> Please.
> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
  2012-03-02  1:09   ` HATAYAMA Daisuke
@ 2012-03-02  1:42     ` Wen Congyang
  0 siblings, 0 replies; 37+ messages in thread
From: Wen Congyang @ 2012-03-02  1:42 UTC (permalink / raw)
  To: HATAYAMA Daisuke; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

At 03/02/2012 09:09 AM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
> Date: Thu, 01 Mar 2012 10:48:17 +0800
> 
>> +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
>> +                             target_phys_addr_t *offset, void *opaque)
>> +{
>> +    QEMUCPUState state;
>> +    Elf64_Nhdr *note;
> 
> <cut>
> 
>> +    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
> 
>                             ELF64_Nhdr?

Yes, it's my misss, and I will fix it.

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
  2012-03-01  6:21     ` Wen Congyang
@ 2012-03-02  2:16       ` HATAYAMA Daisuke
  0 siblings, 0 replies; 37+ messages in thread
From: HATAYAMA Daisuke @ 2012-03-02  2:16 UTC (permalink / raw)
  To: wency; +Cc: jan.kiszka, anderson, qemu-devel, eblake, lcapitulino

From: Wen Congyang <wency@cn.fujitsu.com>
Subject: Re: [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
Date: Thu, 01 Mar 2012 14:21:37 +0800

> At 03/01/2012 02:13 PM, HATAYAMA Daisuke Wrote:
>> From: Wen Congyang <wency@cn.fujitsu.com>
>> Subject: [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping()
>> Date: Thu, 01 Mar 2012 10:41:47 +0800
>> 
>>> +int cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
>>> +{
>>> +    if (env->cr[4] & CR4_PAE_MASK) {
>>> +#ifdef TARGET_X86_64
>>> +        if (env->hflags & HF_LMA_MASK) {
>>> +            target_phys_addr_t pml4e_addr;
>>> +
>>> +            pml4e_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
>>> +            walk_pml4e(list, pml4e_addr, env->a20_mask);
>>> +        } else
>>> +#endif
>>> +        {
>>> +            target_phys_addr_t pdpe_addr;
>>> +
>>> +            pdpe_addr = (env->cr[3] & ~0x1f) & env->a20_mask;
>>> +            walk_pdpe2(list, pdpe_addr, env->a20_mask);
>>> +        }
>>> +    } else {
>>> +        target_phys_addr_t pde_addr;
>>> +        bool pse;
>>> +
>>> +        pde_addr = (env->cr[3] & ~0xfff) & env->a20_mask;
>>> +        pse = !!(env->cr[4] & CR4_PSE_MASK);
>>> +        walk_pde2(list, pde_addr, env->a20_mask, pse);
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>> 
>> Does this assume paging mode? I don't know qemu very well, but qemu
>> dump command runs externally to guest machine, so I think the machine
>> could be in the state with paging disabled where CR4 doesn't refer to
>> page table as expected.
> 
> CR4? I think you want to say CR3.
> 
> Yes, the guest may be in the state without paging mode. I will fix it.
> 

Hmmm, now I think dump command needs to have a option to specify
whether to do paging or not during dumping. Doing always paging is
problematic. Also generated formats should be as simple as possible,
different from the format this current version generates. The reasons
I have are as follows:

  - The qemu dump command runs outside of guest machine. If machine is
    in the state with paging disabled and CR3 doesn't has page table
    address, qemu dump command cannot do paging.

  - We cannot do paging if guest machine state is severe. For example,
    when page table data is corrupted in some reason. In general, we
    should use minimum kinds of data only during dumping.

  - There's also kdump specific issue. On kdump there are two kinds of
    kernels, 1st kernel and 2nd kernel, and when crash happens,
    execution is transmitted from the 1st to the 2nd, and then the 2nd
    kernel copies the 1st kernel's kernel image. The problem is that
    at catastrophic situation, kdump can also hang even in the 2nd
    kernel. At this point, the 2nd kernel refers to the 2nd kernel's
    page table. So paging at the situation leads to lost of the 1st
    kernel's memory.

  - OTOH, gdb cannot perform paging, so, for gdb support, qemu dump
    needs to have paging mode. The period when qemu dump can produce
    the dump gdb can read is limited to the machine state with paging
    enabled and the 1st krenel, but I think no choise.

    * There's a way of getting the 1st kernel's image as linear image
      from the dumpfile generated at the 2nd kernel generated without
      paging. But it uses kenrel's specific information, so I don't
      think qemu should do this.

  - Well, it's possible to generate dumpfile while enabling both
    physical and linear address access together. It's just what Wen is
    doing now. But I think it better to do that more simply: that is,
    if non-paging mode, produce dumpfile as raw format; if paging
    mode, produce as linear format.

    * For example, the current implementation assigns both virtual and
      physical address to a single PT_LOAD entry. But the memory areas
      mapped to by a single PT_LOAD is restricted to the ones
      contiguous both physically and virtually. Due to this, I guess
      there's a case where the number of program headers grows
      seriously in the worst case. It might reach ELF's limit size.

    * Also, by this, it's necessary to reduce the number of program
      headers as much as possible, and now qemu dump tries to merge
      them in PATCH 01, but it looks to me too complicated.

How do other people think?

Thanks.
HATAYAMA, Daisuke

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2012-03-02  2:16 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-01  2:35 [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism Wen Congyang
2012-03-01  2:39 ` [Qemu-devel] [RFC][PATCH 01/14 v7] Add API to create memory mapping list Wen Congyang
2012-03-01  8:33   ` HATAYAMA Daisuke
2012-03-01  8:58     ` Wen Congyang
2012-03-01  2:40 ` [Qemu-devel] [RFC][PATCH 02/14 v7] Add API to check whether a physical address is I/O address Wen Congyang
2012-03-01  2:41 ` [Qemu-devel] [RFC][PATCH 03/14 v7] target-i386: implement cpu_get_memory_mapping() Wen Congyang
2012-03-01  6:13   ` HATAYAMA Daisuke
2012-03-01  6:21     ` Wen Congyang
2012-03-02  2:16       ` HATAYAMA Daisuke
2012-03-01  2:43 ` [Qemu-devel] [RFC][PATCH 04/14 v7] Add API to get memory mapping Wen Congyang
2012-03-01  6:01   ` HATAYAMA Daisuke
2012-03-01  6:17     ` Wen Congyang
2012-03-01  7:11       ` HATAYAMA Daisuke
2012-03-01  7:22         ` Wen Congyang
2012-03-01  2:45 ` [Qemu-devel] [RFC][PATCH 05/14 v7] target-i386: Add API to write elf notes to core file Wen Congyang
2012-03-01  2:48 ` [Qemu-devel] [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status " Wen Congyang
2012-03-01  5:01   ` HATAYAMA Daisuke
2012-03-01  5:05     ` Wen Congyang
2012-03-02  1:30       ` HATAYAMA Daisuke
2012-03-01  5:10   ` HATAYAMA Daisuke
2012-03-01  5:22     ` Wen Congyang
2012-03-02  1:09   ` HATAYAMA Daisuke
2012-03-02  1:42     ` Wen Congyang
2012-03-01  2:49 ` [Qemu-devel] [RFC][PATCH 07/14 v7] target-i386: add API to get dump info Wen Congyang
2012-03-01  2:50 ` [Qemu-devel] [RFC][PATCH 08/14 v7] make gdb_id() generally avialable Wen Congyang
2012-03-01  2:51 ` [Qemu-devel] [RFC][PATCH 09/14 v7] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
2012-03-01  7:04   ` HATAYAMA Daisuke
2012-03-01  7:21     ` Wen Congyang
2012-03-01  2:52 ` [Qemu-devel] [RFC][PATCH 10/14 v7] support to cancel the current dumping Wen Congyang
2012-03-01  2:53 ` [Qemu-devel] [RFC][PATCH 11/14 v7] support to query dumping status Wen Congyang
2012-03-01  2:54 ` [Qemu-devel] [RFC][PATCH 12/14 v7] run dump at the background Wen Congyang
2012-03-01  2:55 ` [Qemu-devel] [RFC][PATCH 13/14 v7] support detached dump Wen Congyang
2012-03-01  2:55 ` [Qemu-devel] [RFC][PATCH 14/14 v7] allow user to dump a fraction of the memory Wen Congyang
2012-03-01  4:42 ` [Qemu-devel] [RFC][PATCH 00/14 v7] introducing a new, dedicated memory dump mechanism HATAYAMA Daisuke
2012-03-01  5:16   ` Wen Congyang
2012-03-02  0:49     ` HATAYAMA Daisuke
2012-03-02  1:39       ` Wen Congyang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.