From: Ruslan Ruslichenko <[email protected]>

The patch adds possibility to read and parse device tree
node properties and set them to newly created object.

Signed-off-by: Ruslan Ruslichenko <[email protected]>
---
 hw/core/fdt_generic_util.c | 222 +++++++++++++++++++++++++++++++++++++
 1 file changed, 222 insertions(+)

diff --git a/hw/core/fdt_generic_util.c b/hw/core/fdt_generic_util.c
index 8131511e70..2a3862b9ac 100644
--- a/hw/core/fdt_generic_util.c
+++ b/hw/core/fdt_generic_util.c
@@ -40,7 +40,9 @@
 #include "qemu/config-file.h"
 #include "hw/core/boards.h"
 #include "qemu/option.h"
+#include "hw/core/qdev-properties.h"
 #include "hw/cpu/cluster.h"
+#include "qobject/qlist.h"
 
 #ifndef FDT_GENERIC_UTIL_ERR_DEBUG
 #define FDT_GENERIC_UTIL_ERR_DEBUG 3
@@ -342,6 +344,25 @@ static Object *fdt_create_from_compat(const char *compat, 
char **dev_type)
     return ret;
 }
 
+/*FIXME: roll into device tree functionality */
+
+static inline uint64_t get_int_be(const void *p, int len)
+{
+    switch (len) {
+    case 1:
+        return *((uint8_t *)p);
+    case 2:
+        return be16_to_cpu(*((uint16_t *)p));
+    case 4:
+        return be32_to_cpu(*((uint32_t *)p));
+    case 8:
+        return be32_to_cpu(*((uint64_t *)p));
+    default:
+        fprintf(stderr, "unsupported integer length\n");
+        abort();
+    }
+}
+
 /*
  * Error handler for device creation failure.
  *
@@ -369,10 +390,185 @@ static void fdt_dev_error(FDTMachineInfo *fdti, char 
*node_path, char *compat)
     }
 }
 
+static void fdt_init_qdev_link_prop(Object *obj, ObjectProperty *p,
+                                    FDTMachineInfo *fdti,
+                                    const char *node_path,
+                                    const QEMUDevtreeProp *prop)
+{
+    int len = prop->len;
+    const void *val = prop->value;
+    const char *propname = prop->name;
+
+    Object *linked_dev, *proxy;
+    char target_node_path[DT_PATH_LENGTH];
+    g_autofree char *propname_target = g_strconcat(propname, "-target", NULL);
+    Error *errp = NULL;
+
+    if (qemu_devtree_get_node_by_phandle(fdti->fdt, target_node_path,
+                                         get_int_be(val, len))) {
+        abort();
+    }
+
+    while (!fdt_init_has_opaque(fdti, target_node_path)) {
+        fdt_init_yield(fdti);
+    }
+    linked_dev = fdt_init_get_opaque(fdti, target_node_path);
+
+    proxy = linked_dev ? object_property_get_link(linked_dev,
+                                                  propname_target,
+                                                  &errp) : NULL;
+    if (!errp && proxy) {
+        DB_PRINT_NP(0, "detected proxy object for %s connection\n", propname);
+        linked_dev = proxy;
+    }
+
+    if (!linked_dev) {
+        linked_dev = object_resolve_link(obj, propname,
+                                         target_node_path, &errp);
+        if (!linked_dev) {
+            return;
+        }
+    }
+
+    errp = NULL;
+    object_property_set_link(obj, propname, linked_dev, &errp);
+    if (errp) {
+        /* Unable to set the property, maybe it is a memory alias? */
+        MemoryRegion *alias_mr;
+        int offset = len / 2;
+        int region = 0;
+
+        if (len > 4) {
+            region = get_int_be(val + offset, len - offset);
+        }
+
+        alias_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(linked_dev), region);
+
+        object_property_set_link(obj, propname, OBJECT(alias_mr), 
&error_abort);
+
+    }
+
+    DB_PRINT_NP(0, "set link %s\n", propname);
+}
+
+static void fdt_init_qdev_scalar_prop(Object *obj, ObjectProperty *p,
+                                      FDTMachineInfo *fdti,
+                                      const char *node_path,
+                                      const QEMUDevtreeProp *prop)
+{
+    const char *propname = trim_vendor(prop->name);
+    const void *val = prop->value;
+    int len = prop->len;
+
+    /* FIXME: handle generically using accessors and stuff */
+    if (!strncmp(p->type, "link", 4)) {
+        fdt_init_qdev_link_prop(obj, p, fdti, node_path, prop);
+        return;
+    }
+
+    if (!strcmp(p->type, "uint8") || !strcmp(p->type, "uint16") ||
+        !strcmp(p->type, "uint32") || !strcmp(p->type, "uint64") ||
+        !strcmp(p->type, "int8") || !strcmp(p->type, "int16") ||
+        !strcmp(p->type, "int32") || !strcmp(p->type, "int64")) {
+        object_property_set_int(obj, propname,
+                                get_int_be(val, len), &error_abort);
+        DB_PRINT_NP(0, "set property %s to 0x%llx\n", propname,
+                    (unsigned long long)get_int_be(val, len));
+        return;
+    }
+
+    if (!strcmp(p->type, "boolean") || !strcmp(p->type, "bool")) {
+        object_property_set_bool(obj, propname,
+                                 !!get_int_be(val, len), &error_abort);
+        DB_PRINT_NP(0, "set property %s to %s\n", propname,
+                    get_int_be(val, len) ? "true" : "false");
+        return;
+    }
+
+    if (!strcmp(p->type, "string") || !strcmp(p->type, "str")) {
+        object_property_set_str(obj, propname,
+                                (const char *)val, &error_abort);
+        DB_PRINT_NP(0, "set property %s to %s\n", propname, (const char *)val);
+        return;
+    }
+
+    DB_PRINT_NP(0, "WARNING: property is of unknown type\n");
+}
+
+static size_t fdt_array_elem_len(FDTMachineInfo *fdti,
+                                 const char *node_path,
+                                 const char *propname)
+{
+    g_autofree char *elem_cells_propname = NULL;
+    Error *err = NULL;
+    uint32_t elem_cells;
+
+    /*
+     * Default element size to 1 uint32_t cell, unless it is explicitly
+     * given in the same FDT node (not inherited).
+     */
+    elem_cells_propname = g_strconcat("#", propname, "-cells", NULL);
+    elem_cells = qemu_fdt_getprop_cell(fdti->fdt, node_path,
+                                       elem_cells_propname, 0, &err);
+
+    return (err ? 1 : elem_cells) * 4;
+}
+
+static void fdt_init_qdev_array_prop(Object *obj,
+                                     FDTMachineInfo *fdti,
+                                     const char *node_path,
+                                     QEMUDevtreeProp *prop)
+{
+    const char *propname = trim_vendor(prop->name);
+    int nr = prop->len;
+    uint32_t elem_len;
+    QList *qlist = qlist_new();
+    const char *prop_type;
+    const void *prop_value = prop->value;
+
+    if (!prop->value || !nr) {
+        return;
+    }
+
+    elem_len = fdt_array_elem_len(fdti, node_path, propname);
+    if (nr % elem_len) {
+        return;
+    }
+
+    nr /= elem_len;
+
+    prop_type = qdev_prop_get_array_elem_type(DEVICE(obj), propname);
+    if (!prop_type) {
+        DB_PRINT_NP(0, "fail to get property array elem type\n");
+        return;
+    }
+
+    while (nr--) {
+        if (!strcmp(prop_type, "uint8") || !strcmp(prop_type, "uint16") ||
+            !strcmp(prop_type, "uint32") || !strcmp(prop_type, "uint64") ||
+            !strcmp(prop_type, "int8") || !strcmp(prop_type, "int16") ||
+            !strcmp(prop_type, "int32") || !strcmp(prop_type, "int64")) {
+                qlist_append_int(qlist, get_int_be(prop_value, elem_len));
+        } else if (!strcmp(prop_type, "boolean") || !strcmp(prop_type, 
"bool")) {
+            qlist_append_bool(qlist, !!get_int_be(prop_value, elem_len));
+        } else if (!strcmp(prop_type, "string") || !strcmp(prop_type, "str")) {
+            qlist_append_str(qlist, (const char *)prop_value);
+        }
+
+        prop_value += elem_len;
+
+        /* TBD: add link type support */
+    }
+
+    qdev_prop_set_array(DEVICE(obj), propname, qlist);
+    DB_PRINT_NP(0, "set property %s propname to <list>\n", propname);
+}
+
 static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat)
 {
     Object *dev, *parent;
     char *dev_type = NULL;
+    QEMUDevtreeProp *prop, *props;
     char parent_node_path[DT_PATH_LENGTH];
 
     if (!compat) {
@@ -460,7 +656,33 @@ static int fdt_init_qdev(char *node_path, FDTMachineInfo 
*fdti, char *compat)
     }
     fdt_init_set_opaque(fdti, node_path, dev);
 
+    props = qemu_devtree_get_props(fdti->fdt, node_path);
+    for (prop = props; prop->name; prop++) {
+        const char *propname = trim_vendor(prop->name);
+        ObjectProperty *p = NULL;
+
+        p = object_property_find(OBJECT(dev), propname);
+        if (p) {
+            DB_PRINT_NP(1, "matched property: %s of type %s, len %d\n",
+                                            propname, p->type, prop->len);
+        }
+        if (!p) {
+            continue;
+        }
+
+        if (!strcmp(p->type, "list")) {
+            fdt_init_qdev_array_prop(dev, fdti, node_path, prop);
+        }
+
+        if (!strcmp(propname, "type")) {
+            continue;
+        }
+
+        fdt_init_qdev_scalar_prop(OBJECT(dev), p, fdti, node_path, prop);
+    }
+
     g_free(dev_type);
+    g_free(props);
 
     return 0;
 }
-- 
2.43.0


Reply via email to