qemu/device_tree.c
<<
>>
Prefs
   1/*
   2 * Functions to help device tree manipulation using libfdt.
   3 * It also provides functions to read entries from device tree proc
   4 * interface.
   5 *
   6 * Copyright 2008 IBM Corporation.
   7 * Authors: Jerone Young <jyoung5@us.ibm.com>
   8 *          Hollis Blanchard <hollisb@us.ibm.com>
   9 *
  10 * This work is licensed under the GNU GPL license version 2 or later.
  11 *
  12 */
  13
  14#include <stdio.h>
  15#include <sys/types.h>
  16#include <sys/stat.h>
  17#include <fcntl.h>
  18#include <unistd.h>
  19#include <stdlib.h>
  20
  21#include "config.h"
  22#include "qemu-common.h"
  23#include "device_tree.h"
  24#include "hw/loader.h"
  25
  26#include <libfdt.h>
  27
  28void *load_device_tree(const char *filename_path, int *sizep)
  29{
  30    int dt_size;
  31    int dt_file_load_size;
  32    int ret;
  33    void *fdt = NULL;
  34
  35    *sizep = 0;
  36    dt_size = get_image_size(filename_path);
  37    if (dt_size < 0) {
  38        printf("Unable to get size of device tree file '%s'\n",
  39            filename_path);
  40        goto fail;
  41    }
  42
  43    /* Expand to 2x size to give enough room for manipulation.  */
  44    dt_size += 10000;
  45    dt_size *= 2;
  46    /* First allocate space in qemu for device tree */
  47    fdt = g_malloc0(dt_size);
  48
  49    dt_file_load_size = load_image(filename_path, fdt);
  50    if (dt_file_load_size < 0) {
  51        printf("Unable to open device tree file '%s'\n",
  52               filename_path);
  53        goto fail;
  54    }
  55
  56    ret = fdt_open_into(fdt, fdt, dt_size);
  57    if (ret) {
  58        printf("Unable to copy device tree in memory\n");
  59        goto fail;
  60    }
  61
  62    /* Check sanity of device tree */
  63    if (fdt_check_header(fdt)) {
  64        printf ("Device tree file loaded into memory is invalid: %s\n",
  65            filename_path);
  66        goto fail;
  67    }
  68    *sizep = dt_size;
  69    return fdt;
  70
  71fail:
  72    g_free(fdt);
  73    return NULL;
  74}
  75
  76static int findnode_nofail(void *fdt, const char *node_path)
  77{
  78    int offset;
  79
  80    offset = fdt_path_offset(fdt, node_path);
  81    if (offset < 0) {
  82        fprintf(stderr, "%s Couldn't find node %s: %s\n", __func__, node_path,
  83                fdt_strerror(offset));
  84        exit(1);
  85    }
  86
  87    return offset;
  88}
  89
  90int qemu_devtree_setprop(void *fdt, const char *node_path,
  91                         const char *property, void *val_array, int size)
  92{
  93    int r;
  94
  95    r = fdt_setprop(fdt, findnode_nofail(fdt, node_path), property, val_array, size);
  96    if (r < 0) {
  97        fprintf(stderr, "%s: Couldn't set %s/%s: %s\n", __func__, node_path,
  98                property, fdt_strerror(r));
  99        exit(1);
 100    }
 101
 102    return r;
 103}
 104
 105int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
 106                              const char *property, uint32_t val)
 107{
 108    int r;
 109
 110    r = fdt_setprop_cell(fdt, findnode_nofail(fdt, node_path), property, val);
 111    if (r < 0) {
 112        fprintf(stderr, "%s: Couldn't set %s/%s = %#08x: %s\n", __func__,
 113                node_path, property, val, fdt_strerror(r));
 114        exit(1);
 115    }
 116
 117    return r;
 118}
 119
 120int qemu_devtree_setprop_string(void *fdt, const char *node_path,
 121                                const char *property, const char *string)
 122{
 123    int r;
 124
 125    r = fdt_setprop_string(fdt, findnode_nofail(fdt, node_path), property, string);
 126    if (r < 0) {
 127        fprintf(stderr, "%s: Couldn't set %s/%s = %s: %s\n", __func__,
 128                node_path, property, string, fdt_strerror(r));
 129        exit(1);
 130    }
 131
 132    return r;
 133}
 134
 135int qemu_devtree_nop_node(void *fdt, const char *node_path)
 136{
 137    int r;
 138
 139    r = fdt_nop_node(fdt, findnode_nofail(fdt, node_path));
 140    if (r < 0) {
 141        fprintf(stderr, "%s: Couldn't nop node %s: %s\n", __func__, node_path,
 142                fdt_strerror(r));
 143        exit(1);
 144    }
 145
 146    return r;
 147}
 148
 149int qemu_devtree_add_subnode(void *fdt, const char *name)
 150{
 151    char *dupname = g_strdup(name);
 152    char *basename = strrchr(dupname, '/');
 153    int retval;
 154
 155    if (!basename) {
 156        g_free(dupname);
 157        return -1;
 158    }
 159
 160    basename[0] = '\0';
 161    basename++;
 162
 163    retval = fdt_add_subnode(fdt, findnode_nofail(fdt, dupname), basename);
 164    if (retval < 0) {
 165        fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name,
 166                fdt_strerror(retval));
 167        exit(1);
 168    }
 169
 170    g_free(dupname);
 171    return retval;
 172}
 173