From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
The patch adds few utility functions for parsing FDT nodes.
The helpers are required for upcoming Hardware device tree
feature.
Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
---
include/system/device_tree.h | 22 ++++
system/device_tree.c | 194 +++++++++++++++++++++++++++++++++++
2 files changed, 216 insertions(+)
diff --git a/include/system/device_tree.h b/include/system/device_tree.h
index 5667ff9538..bc378d38d0 100644
--- a/include/system/device_tree.h
+++ b/include/system/device_tree.h
@@ -116,6 +116,11 @@ const void *qemu_fdt_getprop(void *fdt, const char *node_path,
uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,
const char *property, int cell_id,
Error **errp);
+
+const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,
+ const char *property, int *lenp, Error **errp);
+uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,
+ const char *property, int cell_id, Error **errp);
uint32_t qemu_fdt_get_phandle(void *fdt, const char *path);
uint32_t qemu_fdt_alloc_phandle(void *fdt);
int qemu_fdt_nop_node(void *fdt, const char *node_path);
@@ -191,6 +196,23 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
qdt_tmp); \
})
+/* node queries */
+
+int qemu_devtree_get_num_children(void *fdt, const char *node_path);
+int qemu_devtree_get_children(void *fdt, const char *node_path,
+ int max_paths, char **returned_paths);
+int qemu_devtree_num_props(void *fdt, const char *node_path);
+
+/* node getters */
+
+int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle);
+char *qemu_devtree_getparent(void *fdt, const char *current);
+
+/* misc */
+
+int devtree_get_num_nodes(void *fdt);
+
+#define DT_PATH_LENGTH 1024
/**
* qemu_fdt_randomize_seeds:
diff --git a/system/device_tree.c b/system/device_tree.c
index d2db7bd355..1a70223712 100644
--- a/system/device_tree.c
+++ b/system/device_tree.c
@@ -464,6 +464,96 @@ uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,
return be32_to_cpu(p[cell_id]);
}
+const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,
+ const char *property, int *lenp, Error **errp)
+{
+ const void *found_val = NULL;
+ int found_len = 0;
+ int curr_offset = 0;
+ int temp_len;
+ char **tokens;
+ char **iter;
+
+ found_val = fdt_getprop(fdt, 0, property, &found_len);
+
+ tokens = g_strsplit(node_path + 1, "/", -1);
+
+ for (iter = tokens; *iter != NULL; iter++) {
+ if (**iter == '\0') {
+ continue;
+ }
+
+ curr_offset = fdt_subnode_offset(fdt, curr_offset, *iter);
+ if (curr_offset < 0) {
+ error_setg(errp, "%s: Path '%s' not found",
+ __func__, *iter);
+ g_strfreev(tokens);
+ return NULL;
+ }
+
+ const void *val = fdt_getprop(fdt, curr_offset, property, &temp_len);
+ if (val) {
+ found_val = val;
+ found_len = temp_len;
+ }
+ }
+ g_strfreev(tokens);
+
+ if (!found_val) {
+ error_setg(errp, "%s: Property '%s' not found",
+ __func__, property);
+ return NULL;
+ }
+
+ if (lenp) {
+ *lenp = found_len;
+ }
+
+ return found_val;
+}
+
+uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,
+ const char *property, int cell_id, Error **errp)
+{
+ int len;
+ const uint32_t *p;
+
+ p = qemu_fdt_getprop_inherited(fdt, node_path, property, &len, errp);
+ if (!p) {
+ return 0;
+ }
+ if (len < (cell_id + 1) * 4) {
+ error_setg(errp,
+ "%s: %s/%s is too short, need %d bytes for cell ind %d",
+ __func__, node_path, property, (cell_id + 1) * 4, cell_id);
+ return 0;
+ }
+ return be32_to_cpu(p[cell_id]);
+}
+
+char *qemu_devtree_getparent(void *fdt, const char *current)
+{
+ const char *sep;
+ int len;
+
+ if (!current || !strcmp(current, "/")) {
+ return NULL;
+ }
+
+ sep = strrchr(current, '/');
+ if (!sep) {
+ return NULL;
+ }
+
+ if (sep == current) {
+ len = 1;
+ } else {
+ len = sep - current;
+ }
+
+ return g_strndup(current, len);
+}
+
uint32_t qemu_fdt_get_phandle(void *fdt, const char *path)
{
uint32_t r;
@@ -631,6 +721,110 @@ out:
return ret;
}
+int qemu_devtree_num_props(void *fdt, const char *node_path)
+{
+ int offset = fdt_path_offset(fdt, node_path);
+ int ret = 0;
+
+ for (offset = fdt_first_property_offset(fdt, offset);
+ offset != -FDT_ERR_NOTFOUND;
+ offset = fdt_next_property_offset(fdt, offset)) {
+ ret++;
+ }
+ return ret;
+}
+
+int qemu_devtree_get_children(void *fdt, const char *node_path,
+ int max_paths, char **returned_paths)
+{
+ int count = 0;
+ int subnode;
+ const char *name;
+ int offset = fdt_path_offset(fdt, node_path);
+
+ if (offset < 0) {
+ return offset;
+ }
+
+ bool is_root = (strcmp(node_path, "/") == 0);
+
+ fdt_for_each_subnode(subnode, fdt, offset) {
+ if (count >= max_paths) {
+ break;
+ }
+ name = fdt_get_name(fdt, subnode, NULL);
+ if (returned_paths) {
+ returned_paths[count] = g_strdup_printf("%s/%s",
+ is_root ? "" : node_path, name);
+ }
+
+ ++count;
+ }
+
+ return count;
+}
+
+int qemu_devtree_get_num_children(void *fdt, const char *node_path)
+{
+ int count = 0;
+ int subnode;
+ int offset = fdt_path_offset(fdt, node_path);
+
+ if (offset < 0) {
+ return offset;
+ }
+
+ fdt_for_each_subnode(subnode, fdt, offset) {
+ ++count;
+ }
+
+ return count;
+}
+
+int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle)
+{
+ int offset = 0, cur_depth = 0;
+ int path_lens[64] = { 0 };
+
+ for (offset = 0; offset >= 0; offset = fdt_next_node(fdt, offset,
+ &cur_depth)) {
+ if (cur_depth >= 64) {
+ break;
+ }
+ const char *name = fdt_get_name(fdt, offset, NULL);
+
+ int parent_len = (cur_depth > 0) ? path_lens[cur_depth - 1] : 0;
+ int len = snprintf(node_path + parent_len,
+ DT_PATH_LENGTH - parent_len,
+ "%s%s",
+ (parent_len > 1) ? "/" : "",
+ (cur_depth == 0) ? "/" : name);
+
+ path_lens[cur_depth] = parent_len + len;
+
+ if (fdt_get_phandle(fdt, offset) == phandle) {
+ return 0;
+ }
+ }
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+int devtree_get_num_nodes(void *fdt)
+{
+ int num_nodes = 0;
+ int depth = 0, offset = 0;
+
+ for (;;) {
+ offset = fdt_next_node(fdt, offset, &depth);
+ num_nodes++;
+ if (offset <= 0 || depth <= 0) {
+ break;
+ }
+ }
+ return num_nodes;
+}
+
void qmp_dumpdtb(const char *filename, Error **errp)
{
ERRP_GUARD();
--
2.43.0
On Thu, Apr 02, 2026 at 11:55:47PM +0200, Ruslan Ruslichenko wrote:
> From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
>
> The patch adds few utility functions for parsing FDT nodes.
> The helpers are required for upcoming Hardware device tree
> feature.
If you're building an entire fdt based machine type, it really seems
like you might want a "live" dt representation - the flattened format
is great for communicating between things, but it's not a good data
structure if you're actively consulting it.
>
> Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
> ---
> include/system/device_tree.h | 22 ++++
> system/device_tree.c | 194 +++++++++++++++++++++++++++++++++++
> 2 files changed, 216 insertions(+)
>
> diff --git a/include/system/device_tree.h b/include/system/device_tree.h
> index 5667ff9538..bc378d38d0 100644
> --- a/include/system/device_tree.h
> +++ b/include/system/device_tree.h
> @@ -116,6 +116,11 @@ const void *qemu_fdt_getprop(void *fdt, const char *node_path,
> uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,
> const char *property, int cell_id,
> Error **errp);
> +
> +const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,
> + const char *property, int *lenp, Error **errp);
> +uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,
> + const char *property, int cell_id, Error **errp);
> uint32_t qemu_fdt_get_phandle(void *fdt, const char *path);
> uint32_t qemu_fdt_alloc_phandle(void *fdt);
> int qemu_fdt_nop_node(void *fdt, const char *node_path);
> @@ -191,6 +196,23 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
> qdt_tmp); \
> })
>
> +/* node queries */
> +
> +int qemu_devtree_get_num_children(void *fdt, const char *node_path);
> +int qemu_devtree_get_children(void *fdt, const char *node_path,
> + int max_paths, char **returned_paths);
> +int qemu_devtree_num_props(void *fdt, const char *node_path);
> +
> +/* node getters */
> +
> +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle);
> +char *qemu_devtree_getparent(void *fdt, const char *current);
> +
> +/* misc */
> +
> +int devtree_get_num_nodes(void *fdt);
> +
> +#define DT_PATH_LENGTH 1024
>
> /**
> * qemu_fdt_randomize_seeds:
> diff --git a/system/device_tree.c b/system/device_tree.c
> index d2db7bd355..1a70223712 100644
> --- a/system/device_tree.c
> +++ b/system/device_tree.c
> @@ -464,6 +464,96 @@ uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,
> return be32_to_cpu(p[cell_id]);
> }
>
> +const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,
> + const char *property, int *lenp, Error **errp)
> +{
> + const void *found_val = NULL;
> + int found_len = 0;
> + int curr_offset = 0;
> + int temp_len;
> + char **tokens;
> + char **iter;
> +
> + found_val = fdt_getprop(fdt, 0, property, &found_len);
> +
> + tokens = g_strsplit(node_path + 1, "/", -1);
> +
> + for (iter = tokens; *iter != NULL; iter++) {
> + if (**iter == '\0') {
> + continue;
> + }
> +
> + curr_offset = fdt_subnode_offset(fdt, curr_offset, *iter);
> + if (curr_offset < 0) {
> + error_setg(errp, "%s: Path '%s' not found",
> + __func__, *iter);
> + g_strfreev(tokens);
> + return NULL;
> + }
> +
> + const void *val = fdt_getprop(fdt, curr_offset, property, &temp_len);
> + if (val) {
> + found_val = val;
> + found_len = temp_len;
> + }
> + }
> + g_strfreev(tokens);
> +
> + if (!found_val) {
> + error_setg(errp, "%s: Property '%s' not found",
> + __func__, property);
> + return NULL;
> + }
> +
> + if (lenp) {
> + *lenp = found_len;
> + }
> +
> + return found_val;
> +}
> +
> +uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,
> + const char *property, int cell_id, Error **errp)
> +{
> + int len;
> + const uint32_t *p;
> +
> + p = qemu_fdt_getprop_inherited(fdt, node_path, property, &len, errp);
> + if (!p) {
> + return 0;
> + }
> + if (len < (cell_id + 1) * 4) {
> + error_setg(errp,
> + "%s: %s/%s is too short, need %d bytes for cell ind %d",
> + __func__, node_path, property, (cell_id + 1) * 4, cell_id);
> + return 0;
> + }
> + return be32_to_cpu(p[cell_id]);
> +}
> +
> +char *qemu_devtree_getparent(void *fdt, const char *current)
> +{
> + const char *sep;
> + int len;
> +
> + if (!current || !strcmp(current, "/")) {
> + return NULL;
> + }
> +
> + sep = strrchr(current, '/');
> + if (!sep) {
> + return NULL;
> + }
> +
> + if (sep == current) {
> + len = 1;
> + } else {
> + len = sep - current;
> + }
> +
> + return g_strndup(current, len);
> +}
> +
> uint32_t qemu_fdt_get_phandle(void *fdt, const char *path)
> {
> uint32_t r;
> @@ -631,6 +721,110 @@ out:
> return ret;
> }
>
> +int qemu_devtree_num_props(void *fdt, const char *node_path)
> +{
> + int offset = fdt_path_offset(fdt, node_path);
> + int ret = 0;
> +
> + for (offset = fdt_first_property_offset(fdt, offset);
> + offset != -FDT_ERR_NOTFOUND;
> + offset = fdt_next_property_offset(fdt, offset)) {
> + ret++;
> + }
> + return ret;
> +}
> +
> +int qemu_devtree_get_children(void *fdt, const char *node_path,
> + int max_paths, char **returned_paths)
> +{
> + int count = 0;
> + int subnode;
> + const char *name;
> + int offset = fdt_path_offset(fdt, node_path);
> +
> + if (offset < 0) {
> + return offset;
> + }
> +
> + bool is_root = (strcmp(node_path, "/") == 0);
> +
> + fdt_for_each_subnode(subnode, fdt, offset) {
> + if (count >= max_paths) {
> + break;
> + }
> + name = fdt_get_name(fdt, subnode, NULL);
> + if (returned_paths) {
> + returned_paths[count] = g_strdup_printf("%s/%s",
> + is_root ? "" : node_path, name);
> + }
> +
> + ++count;
> + }
> +
> + return count;
> +}
> +
> +int qemu_devtree_get_num_children(void *fdt, const char *node_path)
> +{
> + int count = 0;
> + int subnode;
> + int offset = fdt_path_offset(fdt, node_path);
> +
> + if (offset < 0) {
> + return offset;
> + }
> +
> + fdt_for_each_subnode(subnode, fdt, offset) {
> + ++count;
> + }
> +
> + return count;
> +}
> +
> +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle)
> +{
> + int offset = 0, cur_depth = 0;
> + int path_lens[64] = { 0 };
> +
> + for (offset = 0; offset >= 0; offset = fdt_next_node(fdt, offset,
> + &cur_depth)) {
> + if (cur_depth >= 64) {
> + break;
> + }
> + const char *name = fdt_get_name(fdt, offset, NULL);
> +
> + int parent_len = (cur_depth > 0) ? path_lens[cur_depth - 1] : 0;
> + int len = snprintf(node_path + parent_len,
> + DT_PATH_LENGTH - parent_len,
> + "%s%s",
> + (parent_len > 1) ? "/" : "",
> + (cur_depth == 0) ? "/" : name);
> +
> + path_lens[cur_depth] = parent_len + len;
> +
> + if (fdt_get_phandle(fdt, offset) == phandle) {
> + return 0;
> + }
> + }
> +
> + return -FDT_ERR_NOTFOUND;
> +}
> +
> +int devtree_get_num_nodes(void *fdt)
> +{
> + int num_nodes = 0;
> + int depth = 0, offset = 0;
> +
> + for (;;) {
> + offset = fdt_next_node(fdt, offset, &depth);
> + num_nodes++;
> + if (offset <= 0 || depth <= 0) {
> + break;
> + }
> + }
> + return num_nodes;
> +}
> +
> void qmp_dumpdtb(const char *filename, Error **errp)
> {
> ERRP_GUARD();
> --
> 2.43.0
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
On Fri, Apr 3, 2026 at 2:52 AM David Gibson <david@gibson.dropbear.id.au> wrote:
>
> On Thu, Apr 02, 2026 at 11:55:47PM +0200, Ruslan Ruslichenko wrote:
> > From: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
> >
> > The patch adds few utility functions for parsing FDT nodes.
> > The helpers are required for upcoming Hardware device tree
> > feature.
>
> If you're building an entire fdt based machine type, it really seems
> like you might want a "live" dt representation - the flattened format
> is great for communicating between things, but it's not a good data
> structure if you're actively consulting it.
>
Hi David,
Thank you for the feedback.
I will look into switching to a live DT representation for the next
version of the series.
BR,
Ruslan
> >
> > Signed-off-by: Ruslan Ruslichenko <Ruslan_Ruslichenko@epam.com>
> > ---
> > include/system/device_tree.h | 22 ++++
> > system/device_tree.c | 194 +++++++++++++++++++++++++++++++++++
> > 2 files changed, 216 insertions(+)
> >
> > diff --git a/include/system/device_tree.h b/include/system/device_tree.h
> > index 5667ff9538..bc378d38d0 100644
> > --- a/include/system/device_tree.h
> > +++ b/include/system/device_tree.h
> > @@ -116,6 +116,11 @@ const void *qemu_fdt_getprop(void *fdt, const char *node_path,
> > uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,
> > const char *property, int cell_id,
> > Error **errp);
> > +
> > +const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,
> > + const char *property, int *lenp, Error **errp);
> > +uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,
> > + const char *property, int cell_id, Error **errp);
> > uint32_t qemu_fdt_get_phandle(void *fdt, const char *path);
> > uint32_t qemu_fdt_alloc_phandle(void *fdt);
> > int qemu_fdt_nop_node(void *fdt, const char *node_path);
> > @@ -191,6 +196,23 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
> > qdt_tmp); \
> > })
> >
> > +/* node queries */
> > +
> > +int qemu_devtree_get_num_children(void *fdt, const char *node_path);
> > +int qemu_devtree_get_children(void *fdt, const char *node_path,
> > + int max_paths, char **returned_paths);
> > +int qemu_devtree_num_props(void *fdt, const char *node_path);
> > +
> > +/* node getters */
> > +
> > +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle);
> > +char *qemu_devtree_getparent(void *fdt, const char *current);
> > +
> > +/* misc */
> > +
> > +int devtree_get_num_nodes(void *fdt);
> > +
> > +#define DT_PATH_LENGTH 1024
> >
> > /**
> > * qemu_fdt_randomize_seeds:
> > diff --git a/system/device_tree.c b/system/device_tree.c
> > index d2db7bd355..1a70223712 100644
> > --- a/system/device_tree.c
> > +++ b/system/device_tree.c
> > @@ -464,6 +464,96 @@ uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,
> > return be32_to_cpu(p[cell_id]);
> > }
> >
> > +const void *qemu_fdt_getprop_inherited(void *fdt, const char *node_path,
> > + const char *property, int *lenp, Error **errp)
> > +{
> > + const void *found_val = NULL;
> > + int found_len = 0;
> > + int curr_offset = 0;
> > + int temp_len;
> > + char **tokens;
> > + char **iter;
> > +
> > + found_val = fdt_getprop(fdt, 0, property, &found_len);
> > +
> > + tokens = g_strsplit(node_path + 1, "/", -1);
> > +
> > + for (iter = tokens; *iter != NULL; iter++) {
> > + if (**iter == '\0') {
> > + continue;
> > + }
> > +
> > + curr_offset = fdt_subnode_offset(fdt, curr_offset, *iter);
> > + if (curr_offset < 0) {
> > + error_setg(errp, "%s: Path '%s' not found",
> > + __func__, *iter);
> > + g_strfreev(tokens);
> > + return NULL;
> > + }
> > +
> > + const void *val = fdt_getprop(fdt, curr_offset, property, &temp_len);
> > + if (val) {
> > + found_val = val;
> > + found_len = temp_len;
> > + }
> > + }
> > + g_strfreev(tokens);
> > +
> > + if (!found_val) {
> > + error_setg(errp, "%s: Property '%s' not found",
> > + __func__, property);
> > + return NULL;
> > + }
> > +
> > + if (lenp) {
> > + *lenp = found_len;
> > + }
> > +
> > + return found_val;
> > +}
> > +
> > +uint32_t qemu_fdt_getprop_cell_inherited(void *fdt, const char *node_path,
> > + const char *property, int cell_id, Error **errp)
> > +{
> > + int len;
> > + const uint32_t *p;
> > +
> > + p = qemu_fdt_getprop_inherited(fdt, node_path, property, &len, errp);
> > + if (!p) {
> > + return 0;
> > + }
> > + if (len < (cell_id + 1) * 4) {
> > + error_setg(errp,
> > + "%s: %s/%s is too short, need %d bytes for cell ind %d",
> > + __func__, node_path, property, (cell_id + 1) * 4, cell_id);
> > + return 0;
> > + }
> > + return be32_to_cpu(p[cell_id]);
> > +}
> > +
> > +char *qemu_devtree_getparent(void *fdt, const char *current)
> > +{
> > + const char *sep;
> > + int len;
> > +
> > + if (!current || !strcmp(current, "/")) {
> > + return NULL;
> > + }
> > +
> > + sep = strrchr(current, '/');
> > + if (!sep) {
> > + return NULL;
> > + }
> > +
> > + if (sep == current) {
> > + len = 1;
> > + } else {
> > + len = sep - current;
> > + }
> > +
> > + return g_strndup(current, len);
> > +}
> > +
> > uint32_t qemu_fdt_get_phandle(void *fdt, const char *path)
> > {
> > uint32_t r;
> > @@ -631,6 +721,110 @@ out:
> > return ret;
> > }
> >
> > +int qemu_devtree_num_props(void *fdt, const char *node_path)
> > +{
> > + int offset = fdt_path_offset(fdt, node_path);
> > + int ret = 0;
> > +
> > + for (offset = fdt_first_property_offset(fdt, offset);
> > + offset != -FDT_ERR_NOTFOUND;
> > + offset = fdt_next_property_offset(fdt, offset)) {
> > + ret++;
> > + }
> > + return ret;
> > +}
> > +
> > +int qemu_devtree_get_children(void *fdt, const char *node_path,
> > + int max_paths, char **returned_paths)
> > +{
> > + int count = 0;
> > + int subnode;
> > + const char *name;
> > + int offset = fdt_path_offset(fdt, node_path);
> > +
> > + if (offset < 0) {
> > + return offset;
> > + }
> > +
> > + bool is_root = (strcmp(node_path, "/") == 0);
> > +
> > + fdt_for_each_subnode(subnode, fdt, offset) {
> > + if (count >= max_paths) {
> > + break;
> > + }
> > + name = fdt_get_name(fdt, subnode, NULL);
> > + if (returned_paths) {
> > + returned_paths[count] = g_strdup_printf("%s/%s",
> > + is_root ? "" : node_path, name);
> > + }
> > +
> > + ++count;
> > + }
> > +
> > + return count;
> > +}
> > +
> > +int qemu_devtree_get_num_children(void *fdt, const char *node_path)
> > +{
> > + int count = 0;
> > + int subnode;
> > + int offset = fdt_path_offset(fdt, node_path);
> > +
> > + if (offset < 0) {
> > + return offset;
> > + }
> > +
> > + fdt_for_each_subnode(subnode, fdt, offset) {
> > + ++count;
> > + }
> > +
> > + return count;
> > +}
> > +
> > +int qemu_devtree_get_node_by_phandle(void *fdt, char *node_path, int phandle)
> > +{
> > + int offset = 0, cur_depth = 0;
> > + int path_lens[64] = { 0 };
> > +
> > + for (offset = 0; offset >= 0; offset = fdt_next_node(fdt, offset,
> > + &cur_depth)) {
> > + if (cur_depth >= 64) {
> > + break;
> > + }
> > + const char *name = fdt_get_name(fdt, offset, NULL);
> > +
> > + int parent_len = (cur_depth > 0) ? path_lens[cur_depth - 1] : 0;
> > + int len = snprintf(node_path + parent_len,
> > + DT_PATH_LENGTH - parent_len,
> > + "%s%s",
> > + (parent_len > 1) ? "/" : "",
> > + (cur_depth == 0) ? "/" : name);
> > +
> > + path_lens[cur_depth] = parent_len + len;
> > +
> > + if (fdt_get_phandle(fdt, offset) == phandle) {
> > + return 0;
> > + }
> > + }
> > +
> > + return -FDT_ERR_NOTFOUND;
> > +}
> > +
> > +int devtree_get_num_nodes(void *fdt)
> > +{
> > + int num_nodes = 0;
> > + int depth = 0, offset = 0;
> > +
> > + for (;;) {
> > + offset = fdt_next_node(fdt, offset, &depth);
> > + num_nodes++;
> > + if (offset <= 0 || depth <= 0) {
> > + break;
> > + }
> > + }
> > + return num_nodes;
> > +}
> > +
> > void qmp_dumpdtb(const char *filename, Error **errp)
> > {
> > ERRP_GUARD();
> > --
> > 2.43.0
> >
>
> --
> David Gibson (he or they) | I'll have my music baroque, and my code
> david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
> | around.
> http://www.ozlabs.org/~dgibson
© 2016 - 2026 Red Hat, Inc.