* [Qemu-devel] [RFC][PATCH 1/8 v3] Add API to create memory mapping list
2011-12-20 8:54 [Qemu-devel] [RFC][PATCT 0/8 v3] dump memory when host pci device is used by guest Wen Congyang
@ 2011-12-20 9:07 ` Wen Congyang
2011-12-20 9:09 ` [Qemu-devel] [RFC][PATCH 2/8 v3] Add API to check whether a physical address is I/O address Wen Congyang
` (6 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Wen Congyang @ 2011-12-20 9:07 UTC (permalink / raw)
To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke
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 | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
memory_mapping.h | 38 ++++++++++++++++
3 files changed, 169 insertions(+), 0 deletions(-)
create mode 100644 memory_mapping.c
create mode 100644 memory_mapping.h
diff --git a/Makefile.target b/Makefile.target
index 3261383..0d5286e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -197,6 +197,7 @@ obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += memory.o
+obj-y += memory_mapping.o
LIBS+=-lz
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
diff --git a/memory_mapping.c b/memory_mapping.c
new file mode 100644
index 0000000..d83b7d7
--- /dev/null
+++ b/memory_mapping.c
@@ -0,0 +1,130 @@
+/*
+ * QEMU 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 "memory_mapping.h"
+
+static MemoryMapping *last_mapping;
+
+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, *p;
+
+ memory_mapping = g_malloc(sizeof(MemoryMapping));
+ memory_mapping->phys_addr = phys_addr;
+ memory_mapping->virt_addr = virt_addr;
+ memory_mapping->length = length;
+ last_mapping = memory_mapping;
+ list->num++;
+ QTAILQ_FOREACH(p, &list->head, next) {
+ if (p->phys_addr >= memory_mapping->phys_addr) {
+ QTAILQ_INSERT_BEFORE(p, memory_mapping, next);
+ return;
+ }
+ }
+ QTAILQ_INSERT_TAIL(&list->head, memory_mapping, next);
+ return;
+}
+
+void create_new_memory_mapping_head(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;
+ last_mapping = memory_mapping;
+ list->num++;
+ QTAILQ_INSERT_HEAD(&list->head, memory_mapping, next);
+ return;
+}
+
+void add_to_memory_mapping(MemoryMappingList *list,
+ target_phys_addr_t phys_addr,
+ target_phys_addr_t virt_addr,
+ ram_addr_t length)
+{
+ MemoryMapping *memory_mapping;
+
+ if (QTAILQ_EMPTY(&list->head)) {
+ create_new_memory_mapping(list, phys_addr, virt_addr, length);
+ return;
+ }
+
+ 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;
+ return;
+ }
+
+ if (!(phys_addr >= (last_mapping->phys_addr)) ||
+ !(phys_addr < (last_mapping->phys_addr + last_mapping->length))) {
+ /* last_mapping does not contain this region */
+ continue;
+ }
+ if (!(virt_addr >= (last_mapping->virt_addr)) ||
+ !(virt_addr < (last_mapping->virt_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 should create another
+ * mapping region.
+ */
+ break;
+ }
+
+ /* merge this region into last_mapping */
+ if ((virt_addr + length) >
+ (last_mapping->virt_addr + last_mapping->length)) {
+ last_mapping->length = virt_addr + length - last_mapping->virt_addr;
+ }
+ return;
+ }
+
+ /* this region can not be merged into any existed memory mapping. */
+ create_new_memory_mapping(list, phys_addr, virt_addr, length);
+ return;
+}
+
+void free_memory_mapping_list(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;
+}
diff --git a/memory_mapping.h b/memory_mapping.h
new file mode 100644
index 0000000..a4b1532
--- /dev/null
+++ b/memory_mapping.h
@@ -0,0 +1,38 @@
+#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;
+ QTAILQ_HEAD(, MemoryMapping) head;
+} MemoryMappingList;
+
+/*
+ * crash needs some memory mapping should be at the head of the list. It will
+ * cause the list is not sorted. So the caller must add the special memory
+ * mapping after adding all the normal memory mapping into list.
+ */
+void create_new_memory_mapping_head(MemoryMappingList *list,
+ target_phys_addr_t phys_addr,
+ target_phys_addr_t virt_addr,
+ ram_addr_t length);
+/*
+ * add or merge the memory region into the memory mapping's list. The list is
+ * sorted by phys_addr.
+ */
+void add_to_memory_mapping(MemoryMappingList *list,
+ target_phys_addr_t phys_addr,
+ target_phys_addr_t virt_addr,
+ ram_addr_t length);
+
+void free_memory_mapping_list(MemoryMappingList *list);
+
+#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [RFC][PATCH 2/8 v3] Add API to check whether a physical address is I/O address
2011-12-20 8:54 [Qemu-devel] [RFC][PATCT 0/8 v3] dump memory when host pci device is used by guest Wen Congyang
2011-12-20 9:07 ` [Qemu-devel] [RFC][PATCH 1/8 v3] Add API to create memory mapping list Wen Congyang
@ 2011-12-20 9:09 ` Wen Congyang
2011-12-20 9:10 ` [Qemu-devel] [RFC][PATCH 3/8 v3] target-i386: implement cpu_get_memory_mapping() Wen Congyang
` (5 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Wen Congyang @ 2011-12-20 9:09 UTC (permalink / raw)
To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke
This API will be used in the following patch.
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
cpu-common.h | 1 +
exec.c | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/cpu-common.h b/cpu-common.h
index 8295e4f..75c01c3 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -91,6 +91,7 @@ struct CPUPhysMemoryClient {
QLIST_ENTRY(CPUPhysMemoryClient) list;
};
+bool is_io_addr(target_phys_addr_t phys_addr);
void cpu_register_phys_memory_client(CPUPhysMemoryClient *);
void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *);
diff --git a/exec.c b/exec.c
index 32782b4..cf0ae8b 100644
--- a/exec.c
+++ b/exec.c
@@ -4853,3 +4853,23 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
#undef env
#endif
+
+bool is_io_addr(target_phys_addr_t phys_addr)
+{
+ ram_addr_t pd;
+ PhysPageDesc *p;
+
+ p = phys_page_find(phys_addr >> TARGET_PAGE_BITS);
+ if (!p) {
+ pd = IO_MEM_UNASSIGNED;
+ } else {
+ pd = p->phys_offset;
+ }
+
+ if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
+ /* I/O region */
+ return true;
+ }
+
+ return false;
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [RFC][PATCH 3/8 v3] target-i386: implement cpu_get_memory_mapping()
2011-12-20 8:54 [Qemu-devel] [RFC][PATCT 0/8 v3] dump memory when host pci device is used by guest Wen Congyang
2011-12-20 9:07 ` [Qemu-devel] [RFC][PATCH 1/8 v3] Add API to create memory mapping list Wen Congyang
2011-12-20 9:09 ` [Qemu-devel] [RFC][PATCH 2/8 v3] Add API to check whether a physical address is I/O address Wen Congyang
@ 2011-12-20 9:10 ` Wen Congyang
2011-12-20 9:11 ` [Qemu-devel] [RFC][PATCH 4/8 v3] Add API to get memory mapping Wen Congyang
` (4 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Wen Congyang @ 2011-12-20 9:10 UTC (permalink / raw)
To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke
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 | 2 +-
cpu-all.h | 7 ++
target-i386/arch-dump.c | 254 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 262 insertions(+), 1 deletions(-)
create mode 100644 target-i386/arch-dump.c
diff --git a/Makefile.target b/Makefile.target
index 0d5286e..29562ad 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -73,7 +73,7 @@ libobj-$(CONFIG_TCG_INTERPRETER) += tci.o
libobj-y += fpu/softfloat.o
libobj-y += op_helper.o helper.o
ifeq ($(TARGET_BASE_ARCH), i386)
-libobj-y += cpuid.o
+libobj-y += cpuid.o arch-dump.o
endif
libobj-$(TARGET_SPARC64) += vis_helper.o
libobj-$(CONFIG_NEED_MMU) += mmu.o
diff --git a/cpu-all.h b/cpu-all.h
index 9d78715..a1f3bc2 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:
*
@@ -584,4 +585,10 @@ 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(TARGET_I386)
+void cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env);
+#else
+#define cpu_get_memory_mapping(list, env)
+#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..2e921c7
--- /dev/null
+++ b/target-i386/arch-dump.c
@@ -0,0 +1,254 @@
+/*
+ * i386 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 "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 (is_io_addr(start_paddr)) {
+ /* I/O region */
+ continue;
+ }
+
+ start_vaddr = start_line_addr | ((i & 0x1fff) << 12);
+ add_to_memory_mapping(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 (is_io_addr(start_paddr)) {
+ /* I/O region */
+ continue;
+ }
+
+ start_vaddr = start_line_addr | ((i & 0x3ff) << 12);
+ add_to_memory_mapping(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 (is_io_addr(start_paddr)) {
+ /* I/O region */
+ continue;
+ }
+ start_vaddr = line_addr;
+ add_to_memory_mapping(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 (is_io_addr(start_paddr)) {
+ /* I/O region */
+ continue;
+ }
+ start_vaddr = line_addr;
+ add_to_memory_mapping(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 (is_io_addr(start_paddr)) {
+ /* I/O region */
+ continue;
+ }
+ start_vaddr = line_addr;
+ add_to_memory_mapping(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
+
+void 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);
+ }
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [RFC][PATCH 4/8 v3] Add API to get memory mapping
2011-12-20 8:54 [Qemu-devel] [RFC][PATCT 0/8 v3] dump memory when host pci device is used by guest Wen Congyang
` (2 preceding siblings ...)
2011-12-20 9:10 ` [Qemu-devel] [RFC][PATCH 3/8 v3] target-i386: implement cpu_get_memory_mapping() Wen Congyang
@ 2011-12-20 9:11 ` Wen Congyang
2011-12-20 9:12 ` [Qemu-devel] [RFC][PATCH 5/8 v3] target-i386: Add API to write elf notes to core file Wen Congyang
` (3 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Wen Congyang @ 2011-12-20 9:11 UTC (permalink / raw)
To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke
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 | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
memory_mapping.h | 1 +
2 files changed, 56 insertions(+), 0 deletions(-)
diff --git a/memory_mapping.c b/memory_mapping.c
index d83b7d7..55c9266 100644
--- a/memory_mapping.c
+++ b/memory_mapping.c
@@ -128,3 +128,58 @@ void free_memory_mapping_list(MemoryMappingList *list)
list->num = 0;
}
+
+void get_memory_mapping(MemoryMappingList *list)
+{
+ CPUState *env;
+ MemoryMapping *memory_mapping;
+ RAMBlock *block;
+ ram_addr_t offset, length;
+
+ last_mapping = NULL;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ cpu_get_memory_mapping(list, env);
+ }
+
+ /* 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'list does not conatin the region
+ * [offset, offset+length)
+ */
+ create_new_memory_mapping(list, offset, 0, length);
+ break;
+ }
+
+ if ((memory_mapping->phys_addr + memory_mapping->length) <=
+ offset) {
+ continue;
+ }
+
+ if (memory_mapping->phys_addr > offset) {
+ /*
+ * memory_mapping'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)) {
+ break;
+ }
+ length -= memory_mapping->phys_addr + memory_mapping->length -
+ offset;
+ offset = memory_mapping->phys_addr + memory_mapping->length;
+ }
+ }
+
+ return;
+}
diff --git a/memory_mapping.h b/memory_mapping.h
index a4b1532..679f9ef 100644
--- a/memory_mapping.h
+++ b/memory_mapping.h
@@ -34,5 +34,6 @@ void add_to_memory_mapping(MemoryMappingList *list,
ram_addr_t length);
void free_memory_mapping_list(MemoryMappingList *list);
+void get_memory_mapping(MemoryMappingList *list);
#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [RFC][PATCH 5/8 v3] target-i386: Add API to write elf notes to core file
2011-12-20 8:54 [Qemu-devel] [RFC][PATCT 0/8 v3] dump memory when host pci device is used by guest Wen Congyang
` (3 preceding siblings ...)
2011-12-20 9:11 ` [Qemu-devel] [RFC][PATCH 4/8 v3] Add API to get memory mapping Wen Congyang
@ 2011-12-20 9:12 ` Wen Congyang
2011-12-20 9:13 ` [Qemu-devel] [RFC][PATCH 6/8 v3] target-i386: Add API to add extra memory mapping Wen Congyang
` (2 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Wen Congyang @ 2011-12-20 9:12 UTC (permalink / raw)
To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke
The core file contains register's value. These API write registers to
core file, and them will be called in the following patch.
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
cpu-all.h | 6 +
target-i386/arch-dump.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 252 insertions(+), 0 deletions(-)
diff --git a/cpu-all.h b/cpu-all.h
index a1f3bc2..038934d 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -587,8 +587,14 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
#if defined(TARGET_I386)
void cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env);
+int cpu_write_elf64_note(Monitor *mon, int fd, CPUState *env, int cpuid,
+ target_phys_addr_t *offset);
+int cpu_write_elf32_note(Monitor *mon, int fd, CPUState *env, int cpuid,
+ target_phys_addr_t *offset);
#else
#define cpu_get_memory_mapping(list, env)
+#define cpu_write_elf64_note(mon, fd, env, cpuid, offset) ({ -1; })
+#define cpu_write_elf32_note(mon, fd, env, cpuid, offset) ({ -1; })
#endif
#endif /* CPU_ALL_H */
diff --git a/target-i386/arch-dump.c b/target-i386/arch-dump.c
index 2e921c7..4ecb981 100644
--- a/target-i386/arch-dump.c
+++ b/target-i386/arch-dump.c
@@ -11,8 +11,11 @@
*
*/
+#include <elf.h>
+
#include "cpu.h"
#include "cpu-all.h"
+#include "monitor.h"
/* PAE Paging or IA-32e Paging */
static void walk_pte(MemoryMappingList *list, target_phys_addr_t pte_start_addr,
@@ -252,3 +255,246 @@ void cpu_get_memory_mapping(MemoryMappingList *list, CPUState *env)
walk_pde2(list, pde_addr, env->a20_mask, pse);
}
}
+
+#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(Monitor *mon, int fd, CPUState *env, int id,
+ target_phys_addr_t *offset)
+{
+ 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, ®s, sizeof(x86_64_user_regs_struct));
+
+ lseek(fd, *offset, SEEK_SET);
+ ret = write(fd, note, note_size);
+ g_free(note);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf prstatus.\n");
+ 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(Monitor *mon, int fd, CPUState *env, int id,
+ target_phys_addr_t *offset)
+{
+ 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, ®s, sizeof(x86_user_regs_struct));
+
+ lseek(fd, *offset, SEEK_SET);
+ ret = write(fd, note, note_size);
+ g_free(note);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf prstatus.\n");
+ return -1;
+ }
+
+ *offset += note_size;
+
+ return 0;
+}
+
+static int x86_write_elf32_note(Monitor *mon, int fd, CPUState *env, int id,
+ target_phys_addr_t *offset)
+{
+ 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, &id, 4); /* pr_pid */
+ buf += descsz - sizeof(x86_user_regs_struct)-4;
+ memcpy(buf, ®s, sizeof(x86_user_regs_struct));
+
+ lseek(fd, *offset, SEEK_SET);
+ ret = write(fd, note, note_size);
+ g_free(note);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf prstatus.\n");
+ return -1;
+ }
+
+ *offset += note_size;
+
+ return 0;
+}
+
+int cpu_write_elf64_note(Monitor *mon, int fd, CPUState *env, int cpuid,
+ target_phys_addr_t *offset)
+{
+ int ret;
+#ifdef TARGET_X86_64
+ bool lma = !!(first_cpu->hflags & HF_LMA_MASK);
+
+ if (lma) {
+ ret = x86_64_write_elf64_note(mon, fd, env, cpuid, offset);
+ } else {
+#endif
+ ret = x86_write_elf64_note(mon, fd, env, cpuid, offset);
+#ifdef TARGET_X86_64
+ }
+#endif
+
+ return ret;
+}
+
+int cpu_write_elf32_note(Monitor *mon, int fd, CPUState *env, int cpuid,
+ target_phys_addr_t *offset)
+{
+ return x86_write_elf32_note(mon, fd, env, cpuid, offset);
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [RFC][PATCH 6/8 v3] target-i386: Add API to add extra memory mapping
2011-12-20 8:54 [Qemu-devel] [RFC][PATCT 0/8 v3] dump memory when host pci device is used by guest Wen Congyang
` (4 preceding siblings ...)
2011-12-20 9:12 ` [Qemu-devel] [RFC][PATCH 5/8 v3] target-i386: Add API to write elf notes to core file Wen Congyang
@ 2011-12-20 9:13 ` Wen Congyang
2011-12-20 9:14 ` [Qemu-devel] [RFC][PATCH 7/8 v3] target-i386: add API to get dump info Wen Congyang
2011-12-20 9:15 ` [Qemu-devel] [RFC][PATCH 8/8 v3] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
7 siblings, 0 replies; 12+ messages in thread
From: Wen Congyang @ 2011-12-20 9:13 UTC (permalink / raw)
To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke
Crash needs extra memory mapping to determine phys_base.
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
cpu-all.h | 2 ++
target-i386/arch-dump.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+), 0 deletions(-)
diff --git a/cpu-all.h b/cpu-all.h
index 038934d..4d87d51 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -591,10 +591,12 @@ int cpu_write_elf64_note(Monitor *mon, int fd, CPUState *env, int cpuid,
target_phys_addr_t *offset);
int cpu_write_elf32_note(Monitor *mon, int fd, CPUState *env, int cpuid,
target_phys_addr_t *offset);
+int cpu_add_extra_memory_mapping(Monitor *mon, MemoryMappingList *list);
#else
#define cpu_get_memory_mapping(list, env)
#define cpu_write_elf64_note(mon, fd, env, cpuid, offset) ({ -1; })
#define cpu_write_elf32_note(mon, fd, env, cpuid, offset) ({ -1; })
+#define cpu_add_extra_memory_mapping(mon, list) ({ 0; })
#endif
#endif /* CPU_ALL_H */
diff --git a/target-i386/arch-dump.c b/target-i386/arch-dump.c
index 4ecb981..2410c6a 100644
--- a/target-i386/arch-dump.c
+++ b/target-i386/arch-dump.c
@@ -498,3 +498,47 @@ int cpu_write_elf32_note(Monitor *mon, int fd, CPUState *env, int cpuid,
{
return x86_write_elf32_note(mon, fd, env, cpuid, offset);
}
+
+/* This function is copied from crash */
+static target_ulong get_phys_base_addr(CPUState *env, target_ulong *base_vaddr)
+{
+ int i;
+ target_ulong kernel_base = -1;
+ target_ulong last, mask;
+
+ for (i = 30, last = -1; (kernel_base == -1) && (i >= 20); i--) {
+ mask = ~((1LL << i) - 1);
+ *base_vaddr = env->idt.base & mask;
+ if (*base_vaddr == last) {
+ continue;
+ }
+
+ kernel_base = cpu_get_phys_page_debug(env, *base_vaddr);
+ last = *base_vaddr;
+ }
+
+ return kernel_base;
+}
+
+int cpu_add_extra_memory_mapping(Monitor *mon, MemoryMappingList *list)
+{
+#ifdef TARGET_X86_64
+ target_phys_addr_t kernel_base = -1;
+ target_ulong base_vaddr;
+ bool lma = !!(first_cpu->hflags & HF_LMA_MASK);
+
+ if (!lma) {
+ return 0;
+ }
+
+ kernel_base = get_phys_base_addr(first_cpu, &base_vaddr);
+ if (kernel_base == -1) {
+ monitor_printf(mon, "dump: can not get phys_base\n");
+ return -1;
+ }
+
+ create_new_memory_mapping_head(list, kernel_base, base_vaddr,
+ TARGET_PAGE_SIZE);
+#endif
+ return 0;
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [RFC][PATCH 7/8 v3] target-i386: add API to get dump info
2011-12-20 8:54 [Qemu-devel] [RFC][PATCT 0/8 v3] dump memory when host pci device is used by guest Wen Congyang
` (5 preceding siblings ...)
2011-12-20 9:13 ` [Qemu-devel] [RFC][PATCH 6/8 v3] target-i386: Add API to add extra memory mapping Wen Congyang
@ 2011-12-20 9:14 ` Wen Congyang
2011-12-20 9:15 ` [Qemu-devel] [RFC][PATCH 8/8 v3] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
7 siblings, 0 replies; 12+ messages in thread
From: Wen Congyang @ 2011-12-20 9:14 UTC (permalink / raw)
To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke
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 | 3 +++
dump.h | 10 ++++++++++
target-i386/arch-dump.c | 34 ++++++++++++++++++++++++++++++++++
3 files changed, 47 insertions(+), 0 deletions(-)
create mode 100644 dump.h
diff --git a/cpu-all.h b/cpu-all.h
index 4d87d51..c53221a 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:
*
@@ -592,11 +593,13 @@ int cpu_write_elf64_note(Monitor *mon, int fd, CPUState *env, int cpuid,
int cpu_write_elf32_note(Monitor *mon, int fd, CPUState *env, int cpuid,
target_phys_addr_t *offset);
int cpu_add_extra_memory_mapping(Monitor *mon, MemoryMappingList *list);
+int cpu_get_dump_info(DumpInfo *info);
#else
#define cpu_get_memory_mapping(list, env)
#define cpu_write_elf64_note(mon, fd, env, cpuid, offset) ({ -1; })
#define cpu_write_elf32_note(mon, fd, env, cpuid, offset) ({ -1; })
#define cpu_add_extra_memory_mapping(mon, list) ({ 0; })
+#define cpu_get_dump_info(info) ({ -1; })
#endif
#endif /* CPU_ALL_H */
diff --git a/dump.h b/dump.h
new file mode 100644
index 0000000..a37de45
--- /dev/null
+++ b/dump.h
@@ -0,0 +1,10 @@
+#ifndef DUMP_H
+#define DUMP_H
+
+typedef struct DumpInfo {
+ int d_machine; /* Architecture */
+ int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
+ int d_class; /* ELFCLASS32 or ELFCLASS64 */
+} DumpInfo;
+
+#endif
diff --git a/target-i386/arch-dump.c b/target-i386/arch-dump.c
index 2410c6a..87b19b6 100644
--- a/target-i386/arch-dump.c
+++ b/target-i386/arch-dump.c
@@ -15,6 +15,7 @@
#include "cpu.h"
#include "cpu-all.h"
+#include "dump.h"
#include "monitor.h"
/* PAE Paging or IA-32e Paging */
@@ -542,3 +543,36 @@ int cpu_add_extra_memory_mapping(Monitor *mon, MemoryMappingList *list)
#endif
return 0;
}
+
+int cpu_get_dump_info(DumpInfo *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 (!lma && (block->offset + block->length > UINT_MAX)) {
+ /* The memory size is greater than 4G */
+ info->d_class = ELFCLASS32;
+ break;
+ }
+ }
+
+ return 0;
+}
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [RFC][PATCH 8/8 v3] introduce a new monitor command 'dump' to dump guest's memory
2011-12-20 8:54 [Qemu-devel] [RFC][PATCT 0/8 v3] dump memory when host pci device is used by guest Wen Congyang
` (6 preceding siblings ...)
2011-12-20 9:14 ` [Qemu-devel] [RFC][PATCH 7/8 v3] target-i386: add API to get dump info Wen Congyang
@ 2011-12-20 9:15 ` Wen Congyang
2011-12-20 16:25 ` Eric Blake
7 siblings, 1 reply; 12+ messages in thread
From: Wen Congyang @ 2011-12-20 9:15 UTC (permalink / raw)
To: qemu-devel, Jan Kiszka, Dave Anderson, HATAYAMA Daisuke
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
Makefile.target | 8 +-
dump.c | 452 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
dump.h | 4 +
hmp-commands.hx | 16 ++
monitor.c | 3 +
qmp-commands.hx | 24 +++
6 files changed, 503 insertions(+), 4 deletions(-)
create mode 100644 dump.c
diff --git a/Makefile.target b/Makefile.target
index 29562ad..f7cc2b9 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -110,7 +110,7 @@ $(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user
obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \
elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \
- user-exec.o $(oslib-obj-y)
+ user-exec.o $(oslib-obj-y) dump.o
obj-$(TARGET_HAS_BFLT) += flatload.o
@@ -148,7 +148,7 @@ LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
LIBS+=-lmx
obj-y = main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o \
- gdbstub.o user-exec.o
+ gdbstub.o user-exec.o dump.o
obj-i386-y += ioport-user.o
@@ -170,7 +170,7 @@ $(call set-vpath, $(SRC_PATH)/bsd-user)
QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
- gdbstub.o uaccess.o user-exec.o
+ gdbstub.o uaccess.o user-exec.o dump.o
obj-i386-y += ioport-user.o
@@ -186,7 +186,7 @@ endif #CONFIG_BSD_USER
# System emulator target
ifdef CONFIG_SOFTMMU
-obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o
+obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o dump.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
obj-$(CONFIG_NO_PCI) += pci-stub.o
diff --git a/dump.c b/dump.c
new file mode 100644
index 0000000..81e466f
--- /dev/null
+++ b/dump.c
@@ -0,0 +1,452 @@
+/*
+ * 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 "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"
+
+#define CPU_CONVERT_TO_TARGET16(val) \
+({ \
+ uint16_t _val = (val); \
+ if (endian == ELFDATA2LSB) { \
+ _val = cpu_to_le16(_val); \
+ } else {\
+ _val = cpu_to_be16(_val); \
+ } \
+ _val; \
+})
+
+#define CPU_CONVERT_TO_TARGET32(val) \
+({ \
+ uint32_t _val = (val); \
+ if (endian == ELFDATA2LSB) { \
+ _val = cpu_to_le32(_val); \
+ } else {\
+ _val = cpu_to_be32(_val); \
+ } \
+ _val; \
+})
+
+#define CPU_CONVERT_TO_TARGET64(val) \
+({ \
+ uint64_t _val = (val); \
+ if (endian == ELFDATA2LSB) { \
+ _val = cpu_to_le64(_val); \
+ } else {\
+ _val = cpu_to_be64(_val); \
+ } \
+ _val; \
+})
+
+static inline int cpuid(CPUState *env)
+{
+#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USE_NPTL)
+ return env->host_tid;
+#else
+ return env->cpu_index + 1;
+#endif
+}
+
+static int write_elf64_header(Monitor *mon, int fd, int phdr_num, int machine,
+ int endian)
+{
+ Elf64_Ehdr elf_header;
+ int ret;
+
+ 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] = endian;
+ elf_header.e_ident[EI_VERSION] = EV_CURRENT;
+ elf_header.e_type = CPU_CONVERT_TO_TARGET16(ET_CORE);
+ elf_header.e_machine = CPU_CONVERT_TO_TARGET16(machine);
+ elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
+ elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
+ elf_header.e_phoff = CPU_CONVERT_TO_TARGET64(sizeof(Elf64_Ehdr));
+ elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf64_Phdr));
+ elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(phdr_num);
+
+ lseek(fd, 0, SEEK_SET);
+ ret = write(fd, &elf_header, sizeof(elf_header));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf header.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf32_header(Monitor *mon, int fd, int phdr_num, int machine,
+ int endian)
+{
+ Elf32_Ehdr elf_header;
+ int ret;
+
+ 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_CONVERT_TO_TARGET16(ET_CORE);
+ elf_header.e_machine = CPU_CONVERT_TO_TARGET16(machine);
+ elf_header.e_version = CPU_CONVERT_TO_TARGET32(EV_CURRENT);
+ elf_header.e_ehsize = CPU_CONVERT_TO_TARGET16(sizeof(elf_header));
+ elf_header.e_phoff = CPU_CONVERT_TO_TARGET32(sizeof(Elf32_Ehdr));
+ elf_header.e_phentsize = CPU_CONVERT_TO_TARGET16(sizeof(Elf32_Phdr));
+ elf_header.e_phnum = CPU_CONVERT_TO_TARGET16(phdr_num);
+
+ lseek(fd, 0, SEEK_SET);
+ ret = write(fd, &elf_header, sizeof(elf_header));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf header.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf64_load(Monitor *mon, int fd, MemoryMapping *memory_mapping,
+ int phdr_index, target_phys_addr_t offset,
+ int endian)
+{
+ Elf64_Phdr phdr;
+ off_t phdr_offset;
+ int ret;
+
+ memset(&phdr, 0, sizeof(Elf64_Phdr));
+ phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
+ phdr.p_offset = CPU_CONVERT_TO_TARGET64(offset);
+ phdr.p_paddr = CPU_CONVERT_TO_TARGET64(memory_mapping->phys_addr);
+ if (offset == -1) {
+ phdr.p_filesz = 0;
+ } else {
+ phdr.p_filesz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
+ }
+ phdr.p_memsz = CPU_CONVERT_TO_TARGET64(memory_mapping->length);
+ phdr.p_vaddr = CPU_CONVERT_TO_TARGET64(memory_mapping->virt_addr);
+
+ phdr_offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_index;
+ lseek(fd, phdr_offset, SEEK_SET);
+ ret = write(fd, &phdr, sizeof(Elf64_Phdr));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write program header table.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf32_load(Monitor *mon, int fd, MemoryMapping *memory_mapping,
+ int phdr_index, target_phys_addr_t offset,
+ int endian)
+{
+ Elf32_Phdr phdr;
+ off_t phdr_offset;
+ int ret;
+
+ memset(&phdr, 0, sizeof(Elf32_Phdr));
+ phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_LOAD);
+ phdr.p_offset = CPU_CONVERT_TO_TARGET32(offset);
+ phdr.p_paddr = CPU_CONVERT_TO_TARGET32(memory_mapping->phys_addr);
+ if (offset == -1) {
+ phdr.p_filesz = 0;
+ } else {
+ phdr.p_filesz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
+ }
+ phdr.p_memsz = CPU_CONVERT_TO_TARGET32(memory_mapping->length);
+ phdr.p_vaddr = CPU_CONVERT_TO_TARGET32(memory_mapping->virt_addr);
+
+ phdr_offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_index;
+ lseek(fd, phdr_offset, SEEK_SET);
+ ret = write(fd, &phdr, sizeof(Elf32_Phdr));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write program header table.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf64_notes(Monitor *mon, int fd, int phdr_index,
+ target_phys_addr_t *offset, int endian)
+{
+ CPUState *env;
+ int ret;
+ target_phys_addr_t begin = *offset;
+ Elf64_Phdr phdr;
+ off_t phdr_offset;
+ int id;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ id = cpuid(env);
+ ret = cpu_write_elf64_note(mon, fd, env, id, offset);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf notes.\n");
+ return -1;
+ }
+ }
+
+ memset(&phdr, 0, sizeof(Elf64_Phdr));
+ phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
+ phdr.p_offset = CPU_CONVERT_TO_TARGET64(begin);
+ phdr.p_paddr = 0;
+ phdr.p_filesz = CPU_CONVERT_TO_TARGET64(*offset - begin);
+ phdr.p_memsz = CPU_CONVERT_TO_TARGET64(*offset - begin);
+ phdr.p_vaddr = 0;
+
+ phdr_offset = sizeof(Elf64_Ehdr);
+ lseek(fd, phdr_offset, SEEK_SET);
+ ret = write(fd, &phdr, sizeof(Elf64_Phdr));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write program header table.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_elf32_notes(Monitor *mon, int fd, int phdr_index,
+ target_phys_addr_t *offset, int endian)
+{
+ CPUState *env;
+ int ret;
+ target_phys_addr_t begin = *offset;
+ Elf32_Phdr phdr;
+ off_t phdr_offset;
+ int id;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ id = cpuid(env);
+ ret = cpu_write_elf32_note(mon, fd, env, id, offset);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write elf notes.\n");
+ return -1;
+ }
+ }
+
+ memset(&phdr, 0, sizeof(Elf32_Phdr));
+ phdr.p_type = CPU_CONVERT_TO_TARGET32(PT_NOTE);
+ phdr.p_offset = CPU_CONVERT_TO_TARGET32(begin);
+ phdr.p_paddr = 0;
+ phdr.p_filesz = CPU_CONVERT_TO_TARGET32(*offset - begin);
+ phdr.p_memsz = CPU_CONVERT_TO_TARGET32(*offset - begin);
+ phdr.p_vaddr = 0;
+
+ phdr_offset = sizeof(Elf32_Ehdr);
+ lseek(fd, phdr_offset, SEEK_SET);
+ ret = write(fd, &phdr, sizeof(Elf32_Phdr));
+ if (ret < 0) {
+ monitor_printf(mon, "dump: failed to write program header table.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int write_data(Monitor *mon, int fd, void *buf, int length,
+ target_phys_addr_t *offset)
+{
+ int ret;
+
+ lseek(fd, *offset, SEEK_SET);
+ ret = write(fd, buf, length);
+ if (ret < 0) {
+ monitor_printf(mon, "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(Monitor *mon, int fd, RAMBlock *block,
+ target_phys_addr_t *offset)
+{
+ int i, ret;
+
+ for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) {
+ ret = write_data(mon, fd, 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(mon, fd, 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;
+}
+
+static int create_vmcore(Monitor *mon, int fd)
+{
+ CPUState *env;
+ target_phys_addr_t offset, memory_offset;
+ int phdr_num, phdr_index;
+ RAMBlock *block;
+ int ret;
+ MemoryMappingList list;
+ MemoryMapping *memory_mapping;
+ DumpInfo info;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ cpu_synchronize_state(env);
+ }
+
+ list.num = 0;
+ QTAILQ_INIT(&list.head);
+ get_memory_mapping(&list);
+
+ ret = cpu_get_dump_info(&info);
+ if (ret < 0) {
+ monitor_printf(mon, "dump: unsupported target.\n");
+ goto error;
+ }
+
+ phdr_num = 1; /* PT_NOTE */
+ /* the type of phdr->num is uint16_t, so we should avoid overflow */
+ if (list.num > (1 << 16) - 2) {
+ phdr_num = (1 << 16) - 1;
+ } else {
+ phdr_num += list.num;
+ }
+
+ /* write elf header to vmcore */
+ if (info.d_class == ELFCLASS64) {
+ ret = write_elf64_header(mon, fd, phdr_num, info.d_machine,
+ info.d_endian);
+ } else {
+ ret = write_elf32_header(mon, fd, phdr_num, info.d_machine,
+ info.d_endian);
+ }
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* write elf notes to vmcore */
+ phdr_index = 0;
+ if (info.d_class == ELFCLASS64) {
+ offset = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phdr_num;
+ ret = write_elf64_notes(mon, fd, phdr_index++, &offset, info.d_endian);
+ } else {
+ offset = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*phdr_num;
+ ret = write_elf32_notes(mon, fd, phdr_index++, &offset, info.d_endian);
+ }
+
+ if (ret < 0) {
+ goto error;
+ }
+
+ memory_offset = offset;
+ /* write all memory to vmcore */
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ ret = write_memory(mon, fd, block, &offset);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ /* write PT_LOAD program header to vmcore */
+ QTAILQ_FOREACH(memory_mapping, &list.head, next) {
+ offset = get_offset(memory_mapping->phys_addr, memory_offset);
+ if (info.d_class == ELFCLASS64) {
+ ret = write_elf64_load(mon, fd, memory_mapping, phdr_index++,
+ offset, info.d_endian);
+ } else {
+ ret = write_elf32_load(mon, fd, memory_mapping, phdr_index++,
+ offset, info.d_endian);
+ }
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ free_memory_mapping_list(&list);
+ return 0;
+
+error:
+ free_memory_mapping_list(&list);
+ return -1;
+}
+
+int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *file = qdict_get_str(qdict, "file");
+ const char *p;
+ int fd = -1;
+
+#if !defined(WIN32)
+ if (strstart(file, "fd:", &p)) {
+ fd = monitor_get_fd(mon, p);
+ if (fd == -1) {
+ monitor_printf(mon, "dump: invalid file descriptor"
+ " identifier\n");
+ return -1;
+ }
+ }
+#endif
+
+ if (strstart(file, "file:", &p)) {
+ fd = open(p, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
+ if (fd < 0) {
+ monitor_printf(mon, "dump: failed to open %s\n", p);
+ return -1;
+ }
+ }
+
+ if (fd == -1) {
+ monitor_printf(mon, "unknown dump protocol: %s\n", file);
+ return -1;
+ }
+
+ vm_stop(RUN_STATE_PAUSED);
+ if (create_vmcore(mon, fd) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/dump.h b/dump.h
index a37de45..0280215 100644
--- a/dump.h
+++ b/dump.h
@@ -1,10 +1,14 @@
#ifndef DUMP_H
#define DUMP_H
+#include "qdict.h"
+
typedef struct DumpInfo {
int d_machine; /* Architecture */
int d_endian; /* ELFDATA2LSB or ELFDATA2MSB */
int d_class; /* ELFCLASS32 or ELFCLASS64 */
} DumpInfo;
+int do_dump(Monitor *mon, const QDict *qdict, QObject **ret_data);
+
#endif
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 14838b7..49faa01 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -767,6 +767,22 @@ Migrate to @var{uri} (using -d to not wait for completion).
ETEXI
{
+ .name = "dump",
+ .args_type = "file:s",
+ .params = "file",
+ .help = "dump to file",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_dump,
+ },
+
+
+STEXI
+@item dump @var{file}
+@findex dump
+Dump to @var{file}.
+ETEXI
+
+ {
.name = "migrate_cancel",
.args_type = "",
.params = "",
diff --git a/monitor.c b/monitor.c
index 7334401..edd6aa7 100644
--- a/monitor.c
+++ b/monitor.c
@@ -73,6 +73,9 @@
#endif
#include "hw/lm32_pic.h"
+/* for dump */
+#include "dump.h"
+
//#define DEBUG
//#define DEBUG_COMPLETION
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7e3f4b9..34c7593 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -469,6 +469,30 @@ Notes:
EQMP
{
+ .name = "dump",
+ .args_type = "file:s",
+ .params = "file",
+ .help = "dump to file",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_dump,
+ },
+
+SQMP
+dump
+-------
+
+Dump to file.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "dump", "arguments": { "file": "fd:dump" } }
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "migrate_cancel",
.args_type = "",
.mhandler.cmd_new = qmp_marshal_input_migrate_cancel,
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC][PATCH 8/8 v3] introduce a new monitor command 'dump' to dump guest's memory
2011-12-20 9:15 ` [Qemu-devel] [RFC][PATCH 8/8 v3] introduce a new monitor command 'dump' to dump guest's memory Wen Congyang
@ 2011-12-20 16:25 ` Eric Blake
2011-12-21 1:10 ` Wen Congyang
2011-12-21 2:42 ` andrzej zaborowski
0 siblings, 2 replies; 12+ messages in thread
From: Eric Blake @ 2011-12-20 16:25 UTC (permalink / raw)
To: Wen Congyang; +Cc: Jan Kiszka, HATAYAMA Daisuke, Dave Anderson, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 1391 bytes --]
On 12/20/2011 02:15 AM, Wen Congyang wrote:
> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
> ---
> Makefile.target | 8 +-
> dump.c | 452 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> dump.h | 4 +
> hmp-commands.hx | 16 ++
> monitor.c | 3 +
> qmp-commands.hx | 24 +++
> 6 files changed, 503 insertions(+), 4 deletions(-)
> create mode 100644 dump.c
>
> +++ b/qmp-commands.hx
> @@ -469,6 +469,30 @@ Notes:
> EQMP
>
> {
> + .name = "dump",
> + .args_type = "file:s",
> + .params = "file",
> + .help = "dump to file",
> + .user_print = monitor_user_noop,
> + .mhandler.cmd_new = do_dump,
> + },
From a libvirt perspective, we would like the option to be able to pass
in an already-open fd rather than just a file name. This is possible if
the 'file' argument is required to start with '/' for an absolute path,
vs. 'file:name' for an fd previously passed in via the getfd monitor
command.
Also, does this command block? It sounds like it is long-running, which
means it probably needs to be asynchronous, as well as issue an event
upon completion, so that other monitor commands can be issued in the
meantime.
--
Eric Blake eblake@redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 620 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC][PATCH 8/8 v3] introduce a new monitor command 'dump' to dump guest's memory
2011-12-20 16:25 ` Eric Blake
@ 2011-12-21 1:10 ` Wen Congyang
2011-12-21 2:42 ` andrzej zaborowski
1 sibling, 0 replies; 12+ messages in thread
From: Wen Congyang @ 2011-12-21 1:10 UTC (permalink / raw)
To: Eric Blake; +Cc: Jan Kiszka, HATAYAMA Daisuke, Dave Anderson, qemu-devel
At 12/21/2011 12:25 AM, Eric Blake Write:
> On 12/20/2011 02:15 AM, Wen Congyang wrote:
>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
>> ---
>> Makefile.target | 8 +-
>> dump.c | 452 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> dump.h | 4 +
>> hmp-commands.hx | 16 ++
>> monitor.c | 3 +
>> qmp-commands.hx | 24 +++
>> 6 files changed, 503 insertions(+), 4 deletions(-)
>> create mode 100644 dump.c
>>
>> +++ b/qmp-commands.hx
>> @@ -469,6 +469,30 @@ Notes:
>> EQMP
>>
>> {
>> + .name = "dump",
>> + .args_type = "file:s",
>> + .params = "file",
>> + .help = "dump to file",
>> + .user_print = monitor_user_noop,
>> + .mhandler.cmd_new = do_dump,
>> + },
>
> From a libvirt perspective, we would like the option to be able to pass
> in an already-open fd rather than just a file name. This is possible if
> the 'file' argument is required to start with '/' for an absolute path,
> vs. 'file:name' for an fd previously passed in via the getfd monitor
> command.
file:s means the parameter is a file, and the type is string.
s can be file:path or fd:fd's name here. Sorry for confusing you.
>
> Also, does this command block? It sounds like it is long-running, which
> means it probably needs to be asynchronous, as well as issue an event
> upon completion, so that other monitor commands can be issued in the
> meantime.
>
Good idea, i will try to implement it in the next version.
Thanks
Wen Congyang
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RFC][PATCH 8/8 v3] introduce a new monitor command 'dump' to dump guest's memory
2011-12-20 16:25 ` Eric Blake
2011-12-21 1:10 ` Wen Congyang
@ 2011-12-21 2:42 ` andrzej zaborowski
1 sibling, 0 replies; 12+ messages in thread
From: andrzej zaborowski @ 2011-12-21 2:42 UTC (permalink / raw)
To: Eric Blake; +Cc: Jan Kiszka, HATAYAMA Daisuke, Dave Anderson, qemu-devel
On 20 December 2011 17:25, Eric Blake <eblake@redhat.com> wrote:
> On 12/20/2011 02:15 AM, Wen Congyang wrote:
>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
>> ---
>> Makefile.target | 8 +-
>> dump.c | 452 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> dump.h | 4 +
>> hmp-commands.hx | 16 ++
>> monitor.c | 3 +
>> qmp-commands.hx | 24 +++
>> 6 files changed, 503 insertions(+), 4 deletions(-)
>> create mode 100644 dump.c
>>
>> +++ b/qmp-commands.hx
>> @@ -469,6 +469,30 @@ Notes:
>> EQMP
>>
>> {
>> + .name = "dump",
>> + .args_type = "file:s",
>> + .params = "file",
>> + .help = "dump to file",
>> + .user_print = monitor_user_noop,
>> + .mhandler.cmd_new = do_dump,
>> + },
>
> From a libvirt perspective, we would like the option to be able to pass
> in an already-open fd rather than just a file name. This is possible if
> the 'file' argument is required to start with '/' for an absolute path,
> vs. 'file:name' for an fd previously passed in via the getfd monitor
> command.
>
> Also, does this command block? It sounds like it is long-running, which
> means it probably needs to be asynchronous, as well as issue an event
> upon completion, so that other monitor commands can be issued in the
> meantime.
Note that it needs to stop the VM and it'd need to prevent other
commands from resuming if this command becomes asynchronous, like
during migration.
Cheers
^ permalink raw reply [flat|nested] 12+ messages in thread