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: Eric Auger <eric.auger@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
		
							parent
							
								
									62d9551247
								
							
						
					
					
						commit
						60e43e987c
					
				
							
								
								
									
										100
									
								
								device_tree.c
								
								
								
								
							
							
						
						
									
										100
									
								
								device_tree.c
								
								
								
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue