Patchwork [RFC,1/5,v2] Add API to create memory mapping list

login
register
mail settings
Submitter Wen Congyang
Date Dec. 9, 2011, 8:06 a.m.
Message ID <4EE1C19D.6060200@cn.fujitsu.com>
Download mbox | patch
Permalink /patch/130314/
State New
Headers show

Comments

Wen Congyang - Dec. 9, 2011, 8:06 a.m.
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 |   29 ++++++++++++
 3 files changed, 160 insertions(+), 0 deletions(-)
 create mode 100644 memory_mapping.c
 create mode 100644 memory_mapping.h
Jan Kiszka - Dec. 13, 2011, 1:03 p.m.
On 2011-12-09 09:06, Wen Congyang wrote:
> 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 |   29 ++++++++++++
>  3 files changed, 160 insertions(+), 0 deletions(-)
>  create mode 100644 memory_mapping.c
>  create mode 100644 memory_mapping.h
> 
> diff --git a/Makefile.target b/Makefile.target
> index a111521..778f514 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -205,6 +205,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;
> +}

Isn't create_new_memory_mapping_head just a special case of
create_new_memory_mapping? And can't add_to_memory_mapping be used or
extended so that create_new_memory_mapping_head becomes obsolete?
Documenting the API would help at least me understanding the different
semantics.

> +
> +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);

Can't last_mapping still point to this object?

> +    }
> +
> +    list->num = 0;
> +}
> diff --git a/memory_mapping.h b/memory_mapping.h
> new file mode 100644
> index 0000000..871591d
> --- /dev/null
> +++ b/memory_mapping.h
> @@ -0,0 +1,29 @@
> +#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;
> +
> +void create_new_memory_mapping_head(MemoryMappingList *list,
> +                                    target_phys_addr_t phys_addr,
> +                                    target_phys_addr_t virt_addr,
> +                                    ram_addr_t length);
> +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

Jan
Wen Congyang - Dec. 14, 2011, 8:10 a.m.
At 12/13/2011 09:03 PM, Jan Kiszka Write:
> On 2011-12-09 09:06, Wen Congyang wrote:
>> 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 |   29 ++++++++++++
>>  3 files changed, 160 insertions(+), 0 deletions(-)
>>  create mode 100644 memory_mapping.c
>>  create mode 100644 memory_mapping.h
>>
>> diff --git a/Makefile.target b/Makefile.target
>> index a111521..778f514 100644
>> --- a/Makefile.target
>> +++ b/Makefile.target
>> @@ -205,6 +205,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;
>> +}
> 
> Isn't create_new_memory_mapping_head just a special case of
> create_new_memory_mapping? And can't add_to_memory_mapping be used or
> extended so that create_new_memory_mapping_head becomes obsolete?
> Documenting the API would help at least me understanding the different
> semantics.

The memory mapping list is sorted by physical address. If the memory mapping's
num is greater than 2^16-2(the length of the value that contains program header
table entry count is 16 bit), we must drop some mappings...

I drop the memory mappings according to physical address, so I sort it.

But crash will use the first PT_LOAD to calculate phys_offset, so I add
the API create_new_memory_mapping_head() to add a specified memory mapping at
the head of the list.

Do you have any better idea?

> 
>> +
>> +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);
> 
> Can't last_mapping still point to this object?

Yes, will fix it(set last_mapping to NULL in get memory mapping())

Thanks for your comment
Wen Congyang

> 
>> +    }
>> +
>> +    list->num = 0;
>> +}
>> diff --git a/memory_mapping.h b/memory_mapping.h
>> new file mode 100644
>> index 0000000..871591d
>> --- /dev/null
>> +++ b/memory_mapping.h
>> @@ -0,0 +1,29 @@
>> +#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;
>> +
>> +void create_new_memory_mapping_head(MemoryMappingList *list,
>> +                                    target_phys_addr_t phys_addr,
>> +                                    target_phys_addr_t virt_addr,
>> +                                    ram_addr_t length);
>> +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
> 
> Jan
>

Patch

diff --git a/Makefile.target b/Makefile.target
index a111521..778f514 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -205,6 +205,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..871591d
--- /dev/null
+++ b/memory_mapping.h
@@ -0,0 +1,29 @@ 
+#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;
+
+void create_new_memory_mapping_head(MemoryMappingList *list,
+                                    target_phys_addr_t phys_addr,
+                                    target_phys_addr_t virt_addr,
+                                    ram_addr_t length);
+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