Skip to content

Commit

Permalink
device_tree: introduce load_device_tree_from_sysfs
Browse files Browse the repository at this point in the history
This function returns the host device tree blob from sysfs
(/proc/device-tree). It uses a recursive function inspired
from dtc read_fstree.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
  • Loading branch information
Eric Auger authored and awilliam committed Feb 19, 2016
1 parent 62d9551 commit 60e43e9
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 0 deletions.
100 changes: 100 additions & 0 deletions device_tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

#include "qemu/osdep.h"

#ifdef CONFIG_LINUX
#include <dirent.h>
#endif

#include "qemu-common.h"
#include "qemu/error-report.h"
#include "sysemu/device_tree.h"
Expand Down Expand Up @@ -112,6 +116,102 @@ void *load_device_tree(const char *filename_path, int *sizep)
return NULL;
}

#ifdef CONFIG_LINUX

#define SYSFS_DT_BASEDIR "/proc/device-tree"

/**
* read_fstree: this function is inspired from dtc read_fstree
* @fdt: preallocated fdt blob buffer, to be populated
* @dirname: directory to scan under SYSFS_DT_BASEDIR
* the search is recursive and the tree is searched down to the
* leaves (property files).
*
* the function asserts in case of error
*/
static void read_fstree(void *fdt, const char *dirname)
{
DIR *d;
struct dirent *de;
struct stat st;
const char *root_dir = SYSFS_DT_BASEDIR;
const char *parent_node;

if (strstr(dirname, root_dir) != dirname) {
error_setg(&error_fatal, "%s: %s must be searched within %s",
__func__, dirname, root_dir);
}
parent_node = &dirname[strlen(SYSFS_DT_BASEDIR)];

d = opendir(dirname);
if (!d) {
error_setg(&error_fatal, "%s cannot open %s", __func__, dirname);
}

while ((de = readdir(d)) != NULL) {
char *tmpnam;

if (!g_strcmp0(de->d_name, ".")
|| !g_strcmp0(de->d_name, "..")) {
continue;
}

tmpnam = g_strdup_printf("%s/%s", dirname, de->d_name);

if (lstat(tmpnam, &st) < 0) {
error_setg(&error_fatal, "%s cannot lstat %s", __func__, tmpnam);
}

if (S_ISREG(st.st_mode)) {
gchar *val;
gsize len;

if (!g_file_get_contents(tmpnam, &val, &len, NULL)) {
error_setg(&error_fatal, "%s not able to extract info from %s",
__func__, tmpnam);
}

if (strlen(parent_node) > 0) {
qemu_fdt_setprop(fdt, parent_node,
de->d_name, val, len);
} else {
qemu_fdt_setprop(fdt, "/", de->d_name, val, len);
}
g_free(val);
} else if (S_ISDIR(st.st_mode)) {
char *node_name;

node_name = g_strdup_printf("%s/%s",
parent_node, de->d_name);
qemu_fdt_add_subnode(fdt, node_name);
g_free(node_name);
read_fstree(fdt, tmpnam);
}

g_free(tmpnam);
}

closedir(d);
}

/* load_device_tree_from_sysfs: extract the dt blob from host sysfs */
void *load_device_tree_from_sysfs(void)
{
void *host_fdt;
int host_fdt_size;

host_fdt = create_device_tree(&host_fdt_size);
read_fstree(host_fdt, SYSFS_DT_BASEDIR);
if (fdt_check_header(host_fdt)) {
error_setg(&error_fatal,
"%s host device tree extracted into memory is invalid",
__func__);
}
return host_fdt;
}

#endif /* CONFIG_LINUX */

static int findnode_nofail(void *fdt, const char *node_path)
{
int offset;
Expand Down
8 changes: 8 additions & 0 deletions include/sysemu/device_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@

void *create_device_tree(int *sizep);
void *load_device_tree(const char *filename_path, int *sizep);
#ifdef CONFIG_LINUX
/**
* load_device_tree_from_sysfs: reads the device tree information in the
* /proc/device-tree directory and return the corresponding binary blob
* buffer pointer. Asserts in case of error.
*/
void *load_device_tree_from_sysfs(void);
#endif

int qemu_fdt_setprop(void *fdt, const char *node_path,
const char *property, const void *val, int size);
Expand Down

0 comments on commit 60e43e9

Please sign in to comment.