Skip to content
Snippets Groups Projects
Commit 60e43e98 authored by Eric Auger's avatar Eric Auger Committed by Alex Williamson
Browse files

device_tree: introduce load_device_tree_from_sysfs


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: default avatarEric Auger <eric.auger@linaro.org>
Reviewed-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 62d95512
No related branches found
No related tags found
No related merge requests found
......@@ -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"
......@@ -112,6 +116,102 @@ fail:
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;
......
......@@ -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);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment