[PATCH v3 21/33] hw/arm/arm_generic_fdt: Add support for host-backed RAM regions

Ruslan Ruslichenko posted 33 patches 1 week, 1 day ago
Maintainers: Peter Maydell <peter.maydell@linaro.org>, Paolo Bonzini <pbonzini@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Alistair Francis <alistair.francis@wdc.com>, David Gibson <david@gibson.dropbear.id.au>, Peter Xu <peterx@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>
[PATCH v3 21/33] hw/arm/arm_generic_fdt: Add support for host-backed RAM regions
Posted by Ruslan Ruslichenko 1 week, 1 day ago
From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>

Add the ability to dynamically map QEMU host memory backends to
guest memory using configuration from the Device Tree.

To map a host memory backend, memory region nodes with the
'qemu-memory-region' compatible string and the 'qemu,ram' property
must specify a 'qemu,host-id' property containing the memdev name.

The corresponding memory backends can be specified via the command line:

...
-object memory-backend-file,id=mem0,mem-path=memory.img,size=256M
...

If no host backend is found, the initialization will fall back to
standard anonymous memory mapping.

Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
---
 hw/arm/arm_generic_fdt.c | 96 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 95 insertions(+), 1 deletion(-)

diff --git a/hw/arm/arm_generic_fdt.c b/hw/arm/arm_generic_fdt.c
index 7b50957a82..de121820e0 100644
--- a/hw/arm/arm_generic_fdt.c
+++ b/hw/arm/arm_generic_fdt.c
@@ -43,6 +43,98 @@ struct ARMGenericFDTState {
 
 OBJECT_DECLARE_SIMPLE_TYPE(ARMGenericFDTState, ARM_GENERIC_FDT_MACHINE)
 
+static void map_host_memdev_node(FDTMachineInfo *fdti, const char *node_path)
+{
+    int len;
+    uint64_t mr_size, backed_size;
+    Object *mem_obj;
+    Object *backend_obj;
+    MemoryRegion *mr;
+    MemoryRegion *backend_mr;
+    MemoryRegion *container;
+    HostMemoryBackend *backend_mem;
+
+    const char *compat = qemu_fdt_getprop(fdti->fdt, node_path,
+                                          "compatible", &len, NULL);
+    const char *host_id = qemu_fdt_getprop(fdti->fdt, node_path, "qemu,host-id",
+                                           &len, NULL);
+    bool is_qemu_ram = (qemu_fdt_getprop(fdti->fdt, node_path, "qemu,ram",
+                                         &len, NULL) != NULL);
+
+    if (!compat || strcmp(compat, "qemu-memory-region")) {
+        return;
+    }
+
+    if (!is_qemu_ram || !host_id) {
+        return;
+    }
+
+    mem_obj = fdt_init_get_opaque(fdti, node_path);
+    if (!mem_obj) {
+        return;
+    }
+
+    backend_obj = object_resolve_path_type(host_id, TYPE_MEMORY_BACKEND,
+                                            NULL);
+    if (!backend_obj) {
+        warn_report("No mem backend found for FDT requested host-id %s",
+                    host_id);
+        return;
+    }
+
+    backend_mem = MEMORY_BACKEND(backend_obj);
+    backend_mr = host_memory_backend_get_memory(backend_mem);
+
+    mr = MEMORY_REGION(mem_obj);
+    container = mr->container;
+    if (!container) {
+        warn_report("No parent found for requested host-id %s",
+                    host_id);
+        return;
+    }
+
+    mr_size = memory_region_size(mr);
+    backed_size = memory_region_size(backend_mr);
+
+    if (backed_size != mr_size) {
+        error_report("Unable to map host backed memory: %s, "
+                        "dts size: 0x%" PRIx64 ", but memdev size: 0x%" PRIx64,
+                        host_id, mr_size, backed_size);
+        exit(1);
+    }
+
+    hwaddr base_addr = mr->addr;
+
+    memory_region_del_subregion(container, mr);
+    memory_region_add_subregion(container, base_addr, backend_mr);
+
+    fdt_init_set_opaque(fdti, node_path, OBJECT(backend_mr));
+    object_unparent(mem_obj);
+}
+
+/* Parse device-tree starting from 'node' and attach file-backed RAM's */
+static void map_host_memdevs(FDTMachineInfo *fdti, const char *node_path)
+{
+    int i;
+    char **children;
+    int num_children = qemu_devtree_get_num_children(fdti->fdt, node_path);
+
+    if (num_children > 0) {
+        children = g_malloc0(sizeof(*children) * num_children);
+
+        num_children = qemu_devtree_get_children(fdti->fdt, node_path,
+                                      num_children, children);
+        for (i = 0; i < num_children; ++i) {
+            map_host_memdevs(fdti, children[i]);
+            g_free(children[i]);
+        }
+
+        g_free(children);
+    }
+
+    map_host_memdev_node(fdti, node_path);
+}
+
 static void init_machine(void *fdt, ARMGenericFDTState *s)
 {
     FDTMachineInfo *fdti;
@@ -63,7 +155,9 @@ static void init_machine(void *fdt, ARMGenericFDTState *s)
     /* Instantiate peripherals from the FDT.  */
     fdti = fdt_generic_create_machine(fdt, NULL);
 
-    mem_area = MEMORY_REGION(object_resolve_path(node_path[0], NULL));
+    map_host_memdevs(fdti, "/");
+
+    mem_area = MEMORY_REGION(fdt_init_get_opaque(fdti, node_path[0]));
 
     s->bootinfo.loader_start = object_property_get_int(OBJECT(mem_area),
                                                             "addr", NULL);
-- 
2.43.0