Statistics
| Branch: | Revision:

root / device_tree.c @ 5b50e790

History | View | Annotate | Download (8.6 kB)

1 f652e6af aurel32
/*
2 f652e6af aurel32
 * Functions to help device tree manipulation using libfdt.
3 f652e6af aurel32
 * It also provides functions to read entries from device tree proc
4 f652e6af aurel32
 * interface.
5 f652e6af aurel32
 *
6 f652e6af aurel32
 * Copyright 2008 IBM Corporation.
7 f652e6af aurel32
 * Authors: Jerone Young <jyoung5@us.ibm.com>
8 f652e6af aurel32
 *          Hollis Blanchard <hollisb@us.ibm.com>
9 f652e6af aurel32
 *
10 f652e6af aurel32
 * This work is licensed under the GNU GPL license version 2 or later.
11 f652e6af aurel32
 *
12 f652e6af aurel32
 */
13 f652e6af aurel32
14 f652e6af aurel32
#include <stdio.h>
15 f652e6af aurel32
#include <sys/types.h>
16 f652e6af aurel32
#include <sys/stat.h>
17 f652e6af aurel32
#include <fcntl.h>
18 f652e6af aurel32
#include <unistd.h>
19 f652e6af aurel32
#include <stdlib.h>
20 f652e6af aurel32
21 f652e6af aurel32
#include "config.h"
22 f652e6af aurel32
#include "qemu-common.h"
23 9c17d615 Paolo Bonzini
#include "sysemu/device_tree.h"
24 2ff3de68 Markus Armbruster
#include "sysemu/sysemu.h"
25 39b7f20e Blue Swirl
#include "hw/loader.h"
26 1de7afc9 Paolo Bonzini
#include "qemu/option.h"
27 1de7afc9 Paolo Bonzini
#include "qemu/config-file.h"
28 f652e6af aurel32
29 f652e6af aurel32
#include <libfdt.h>
30 f652e6af aurel32
31 ce36252c Alexander Graf
#define FDT_MAX_SIZE  0x10000
32 ce36252c Alexander Graf
33 ce36252c Alexander Graf
void *create_device_tree(int *sizep)
34 ce36252c Alexander Graf
{
35 ce36252c Alexander Graf
    void *fdt;
36 ce36252c Alexander Graf
    int ret;
37 ce36252c Alexander Graf
38 ce36252c Alexander Graf
    *sizep = FDT_MAX_SIZE;
39 ce36252c Alexander Graf
    fdt = g_malloc0(FDT_MAX_SIZE);
40 ce36252c Alexander Graf
    ret = fdt_create(fdt, FDT_MAX_SIZE);
41 ce36252c Alexander Graf
    if (ret < 0) {
42 ce36252c Alexander Graf
        goto fail;
43 ce36252c Alexander Graf
    }
44 ce36252c Alexander Graf
    ret = fdt_begin_node(fdt, "");
45 ce36252c Alexander Graf
    if (ret < 0) {
46 ce36252c Alexander Graf
        goto fail;
47 ce36252c Alexander Graf
    }
48 ce36252c Alexander Graf
    ret = fdt_end_node(fdt);
49 ce36252c Alexander Graf
    if (ret < 0) {
50 ce36252c Alexander Graf
        goto fail;
51 ce36252c Alexander Graf
    }
52 ce36252c Alexander Graf
    ret = fdt_finish(fdt);
53 ce36252c Alexander Graf
    if (ret < 0) {
54 ce36252c Alexander Graf
        goto fail;
55 ce36252c Alexander Graf
    }
56 ce36252c Alexander Graf
    ret = fdt_open_into(fdt, fdt, *sizep);
57 ce36252c Alexander Graf
    if (ret) {
58 ce36252c Alexander Graf
        fprintf(stderr, "Unable to copy device tree in memory\n");
59 ce36252c Alexander Graf
        exit(1);
60 ce36252c Alexander Graf
    }
61 ce36252c Alexander Graf
62 ce36252c Alexander Graf
    return fdt;
63 ce36252c Alexander Graf
fail:
64 ce36252c Alexander Graf
    fprintf(stderr, "%s Couldn't create dt: %s\n", __func__, fdt_strerror(ret));
65 ce36252c Alexander Graf
    exit(1);
66 ce36252c Alexander Graf
}
67 ce36252c Alexander Graf
68 7ec632b4 pbrook
void *load_device_tree(const char *filename_path, int *sizep)
69 f652e6af aurel32
{
70 7ec632b4 pbrook
    int dt_size;
71 f652e6af aurel32
    int dt_file_load_size;
72 f652e6af aurel32
    int ret;
73 7ec632b4 pbrook
    void *fdt = NULL;
74 f652e6af aurel32
75 7ec632b4 pbrook
    *sizep = 0;
76 7ec632b4 pbrook
    dt_size = get_image_size(filename_path);
77 7ec632b4 pbrook
    if (dt_size < 0) {
78 f652e6af aurel32
        printf("Unable to get size of device tree file '%s'\n",
79 f652e6af aurel32
            filename_path);
80 f652e6af aurel32
        goto fail;
81 f652e6af aurel32
    }
82 f652e6af aurel32
83 7ec632b4 pbrook
    /* Expand to 2x size to give enough room for manipulation.  */
84 ded57c5f Alexander Graf
    dt_size += 10000;
85 7ec632b4 pbrook
    dt_size *= 2;
86 f652e6af aurel32
    /* First allocate space in qemu for device tree */
87 7267c094 Anthony Liguori
    fdt = g_malloc0(dt_size);
88 f652e6af aurel32
89 7ec632b4 pbrook
    dt_file_load_size = load_image(filename_path, fdt);
90 7ec632b4 pbrook
    if (dt_file_load_size < 0) {
91 7ec632b4 pbrook
        printf("Unable to open device tree file '%s'\n",
92 7ec632b4 pbrook
               filename_path);
93 7ec632b4 pbrook
        goto fail;
94 7ec632b4 pbrook
    }
95 f652e6af aurel32
96 7ec632b4 pbrook
    ret = fdt_open_into(fdt, fdt, dt_size);
97 f652e6af aurel32
    if (ret) {
98 f652e6af aurel32
        printf("Unable to copy device tree in memory\n");
99 f652e6af aurel32
        goto fail;
100 f652e6af aurel32
    }
101 f652e6af aurel32
102 f652e6af aurel32
    /* Check sanity of device tree */
103 f652e6af aurel32
    if (fdt_check_header(fdt)) {
104 f652e6af aurel32
        printf ("Device tree file loaded into memory is invalid: %s\n",
105 f652e6af aurel32
            filename_path);
106 f652e6af aurel32
        goto fail;
107 f652e6af aurel32
    }
108 7ec632b4 pbrook
    *sizep = dt_size;
109 f652e6af aurel32
    return fdt;
110 f652e6af aurel32
111 f652e6af aurel32
fail:
112 7267c094 Anthony Liguori
    g_free(fdt);
113 f652e6af aurel32
    return NULL;
114 f652e6af aurel32
}
115 f652e6af aurel32
116 ccbcfedd Alexander Graf
static int findnode_nofail(void *fdt, const char *node_path)
117 f652e6af aurel32
{
118 f652e6af aurel32
    int offset;
119 f652e6af aurel32
120 f652e6af aurel32
    offset = fdt_path_offset(fdt, node_path);
121 ccbcfedd Alexander Graf
    if (offset < 0) {
122 ccbcfedd Alexander Graf
        fprintf(stderr, "%s Couldn't find node %s: %s\n", __func__, node_path,
123 ccbcfedd Alexander Graf
                fdt_strerror(offset));
124 ccbcfedd Alexander Graf
        exit(1);
125 ccbcfedd Alexander Graf
    }
126 ccbcfedd Alexander Graf
127 ccbcfedd Alexander Graf
    return offset;
128 ccbcfedd Alexander Graf
}
129 ccbcfedd Alexander Graf
130 ccbcfedd Alexander Graf
int qemu_devtree_setprop(void *fdt, const char *node_path,
131 45e9dfb2 Alexander Graf
                         const char *property, const void *val_array, int size)
132 ccbcfedd Alexander Graf
{
133 ccbcfedd Alexander Graf
    int r;
134 ccbcfedd Alexander Graf
135 ccbcfedd Alexander Graf
    r = fdt_setprop(fdt, findnode_nofail(fdt, node_path), property, val_array, size);
136 ccbcfedd Alexander Graf
    if (r < 0) {
137 ccbcfedd Alexander Graf
        fprintf(stderr, "%s: Couldn't set %s/%s: %s\n", __func__, node_path,
138 ccbcfedd Alexander Graf
                property, fdt_strerror(r));
139 ccbcfedd Alexander Graf
        exit(1);
140 ccbcfedd Alexander Graf
    }
141 f652e6af aurel32
142 ccbcfedd Alexander Graf
    return r;
143 f652e6af aurel32
}
144 f652e6af aurel32
145 f652e6af aurel32
int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
146 f652e6af aurel32
                              const char *property, uint32_t val)
147 f652e6af aurel32
{
148 ccbcfedd Alexander Graf
    int r;
149 f652e6af aurel32
150 ccbcfedd Alexander Graf
    r = fdt_setprop_cell(fdt, findnode_nofail(fdt, node_path), property, val);
151 ccbcfedd Alexander Graf
    if (r < 0) {
152 ccbcfedd Alexander Graf
        fprintf(stderr, "%s: Couldn't set %s/%s = %#08x: %s\n", __func__,
153 ccbcfedd Alexander Graf
                node_path, property, val, fdt_strerror(r));
154 ccbcfedd Alexander Graf
        exit(1);
155 ccbcfedd Alexander Graf
    }
156 f652e6af aurel32
157 ccbcfedd Alexander Graf
    return r;
158 f652e6af aurel32
}
159 f652e6af aurel32
160 bb28eb37 Alexander Graf
int qemu_devtree_setprop_u64(void *fdt, const char *node_path,
161 bb28eb37 Alexander Graf
                             const char *property, uint64_t val)
162 bb28eb37 Alexander Graf
{
163 bb28eb37 Alexander Graf
    val = cpu_to_be64(val);
164 bb28eb37 Alexander Graf
    return qemu_devtree_setprop(fdt, node_path, property, &val, sizeof(val));
165 bb28eb37 Alexander Graf
}
166 bb28eb37 Alexander Graf
167 f652e6af aurel32
int qemu_devtree_setprop_string(void *fdt, const char *node_path,
168 f652e6af aurel32
                                const char *property, const char *string)
169 f652e6af aurel32
{
170 ccbcfedd Alexander Graf
    int r;
171 f652e6af aurel32
172 ccbcfedd Alexander Graf
    r = fdt_setprop_string(fdt, findnode_nofail(fdt, node_path), property, string);
173 ccbcfedd Alexander Graf
    if (r < 0) {
174 ccbcfedd Alexander Graf
        fprintf(stderr, "%s: Couldn't set %s/%s = %s: %s\n", __func__,
175 ccbcfedd Alexander Graf
                node_path, property, string, fdt_strerror(r));
176 ccbcfedd Alexander Graf
        exit(1);
177 ccbcfedd Alexander Graf
    }
178 f652e6af aurel32
179 ccbcfedd Alexander Graf
    return r;
180 f652e6af aurel32
}
181 d69a8e63 Alexander Graf
182 f0aa713f Peter Maydell
const void *qemu_devtree_getprop(void *fdt, const char *node_path,
183 f0aa713f Peter Maydell
                                 const char *property, int *lenp)
184 f0aa713f Peter Maydell
{
185 f0aa713f Peter Maydell
    int len;
186 f0aa713f Peter Maydell
    const void *r;
187 f0aa713f Peter Maydell
    if (!lenp) {
188 f0aa713f Peter Maydell
        lenp = &len;
189 f0aa713f Peter Maydell
    }
190 f0aa713f Peter Maydell
    r = fdt_getprop(fdt, findnode_nofail(fdt, node_path), property, lenp);
191 f0aa713f Peter Maydell
    if (!r) {
192 f0aa713f Peter Maydell
        fprintf(stderr, "%s: Couldn't get %s/%s: %s\n", __func__,
193 f0aa713f Peter Maydell
                node_path, property, fdt_strerror(*lenp));
194 f0aa713f Peter Maydell
        exit(1);
195 f0aa713f Peter Maydell
    }
196 f0aa713f Peter Maydell
    return r;
197 f0aa713f Peter Maydell
}
198 f0aa713f Peter Maydell
199 f0aa713f Peter Maydell
uint32_t qemu_devtree_getprop_cell(void *fdt, const char *node_path,
200 f0aa713f Peter Maydell
                                   const char *property)
201 f0aa713f Peter Maydell
{
202 f0aa713f Peter Maydell
    int len;
203 f0aa713f Peter Maydell
    const uint32_t *p = qemu_devtree_getprop(fdt, node_path, property, &len);
204 f0aa713f Peter Maydell
    if (len != 4) {
205 f0aa713f Peter Maydell
        fprintf(stderr, "%s: %s/%s not 4 bytes long (not a cell?)\n",
206 f0aa713f Peter Maydell
                __func__, node_path, property);
207 f0aa713f Peter Maydell
        exit(1);
208 f0aa713f Peter Maydell
    }
209 f0aa713f Peter Maydell
    return be32_to_cpu(*p);
210 f0aa713f Peter Maydell
}
211 f0aa713f Peter Maydell
212 7d5fd108 Alexander Graf
uint32_t qemu_devtree_get_phandle(void *fdt, const char *path)
213 7d5fd108 Alexander Graf
{
214 7d5fd108 Alexander Graf
    uint32_t r;
215 7d5fd108 Alexander Graf
216 7d5fd108 Alexander Graf
    r = fdt_get_phandle(fdt, findnode_nofail(fdt, path));
217 909a196d Stefan Weil
    if (r == 0) {
218 7d5fd108 Alexander Graf
        fprintf(stderr, "%s: Couldn't get phandle for %s: %s\n", __func__,
219 7d5fd108 Alexander Graf
                path, fdt_strerror(r));
220 7d5fd108 Alexander Graf
        exit(1);
221 7d5fd108 Alexander Graf
    }
222 7d5fd108 Alexander Graf
223 7d5fd108 Alexander Graf
    return r;
224 7d5fd108 Alexander Graf
}
225 7d5fd108 Alexander Graf
226 8535ab12 Alexander Graf
int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
227 8535ab12 Alexander Graf
                                 const char *property,
228 8535ab12 Alexander Graf
                                 const char *target_node_path)
229 8535ab12 Alexander Graf
{
230 7d5fd108 Alexander Graf
    uint32_t phandle = qemu_devtree_get_phandle(fdt, target_node_path);
231 8535ab12 Alexander Graf
    return qemu_devtree_setprop_cell(fdt, node_path, property, phandle);
232 8535ab12 Alexander Graf
}
233 8535ab12 Alexander Graf
234 3601b572 Alexander Graf
uint32_t qemu_devtree_alloc_phandle(void *fdt)
235 3601b572 Alexander Graf
{
236 4b1b1c89 Alexander Graf
    static int phandle = 0x0;
237 4b1b1c89 Alexander Graf
238 4b1b1c89 Alexander Graf
    /*
239 4b1b1c89 Alexander Graf
     * We need to find out if the user gave us special instruction at
240 4b1b1c89 Alexander Graf
     * which phandle id to start allocting phandles.
241 4b1b1c89 Alexander Graf
     */
242 4b1b1c89 Alexander Graf
    if (!phandle) {
243 c1b71b0c Markus Armbruster
        phandle = qemu_opt_get_number(qemu_get_machine_opts(),
244 c1b71b0c Markus Armbruster
                                      "phandle_start", 0);
245 4b1b1c89 Alexander Graf
    }
246 4b1b1c89 Alexander Graf
247 4b1b1c89 Alexander Graf
    if (!phandle) {
248 4b1b1c89 Alexander Graf
        /*
249 4b1b1c89 Alexander Graf
         * None or invalid phandle given on the command line, so fall back to
250 4b1b1c89 Alexander Graf
         * default starting point.
251 4b1b1c89 Alexander Graf
         */
252 4b1b1c89 Alexander Graf
        phandle = 0x8000;
253 4b1b1c89 Alexander Graf
    }
254 3601b572 Alexander Graf
255 3601b572 Alexander Graf
    return phandle++;
256 3601b572 Alexander Graf
}
257 3601b572 Alexander Graf
258 d69a8e63 Alexander Graf
int qemu_devtree_nop_node(void *fdt, const char *node_path)
259 d69a8e63 Alexander Graf
{
260 ccbcfedd Alexander Graf
    int r;
261 d69a8e63 Alexander Graf
262 ccbcfedd Alexander Graf
    r = fdt_nop_node(fdt, findnode_nofail(fdt, node_path));
263 ccbcfedd Alexander Graf
    if (r < 0) {
264 ccbcfedd Alexander Graf
        fprintf(stderr, "%s: Couldn't nop node %s: %s\n", __func__, node_path,
265 ccbcfedd Alexander Graf
                fdt_strerror(r));
266 ccbcfedd Alexander Graf
        exit(1);
267 ccbcfedd Alexander Graf
    }
268 d69a8e63 Alexander Graf
269 ccbcfedd Alexander Graf
    return r;
270 d69a8e63 Alexander Graf
}
271 80ad7816 Alexander Graf
272 80ad7816 Alexander Graf
int qemu_devtree_add_subnode(void *fdt, const char *name)
273 80ad7816 Alexander Graf
{
274 80ad7816 Alexander Graf
    char *dupname = g_strdup(name);
275 80ad7816 Alexander Graf
    char *basename = strrchr(dupname, '/');
276 80ad7816 Alexander Graf
    int retval;
277 c640d088 Alexander Graf
    int parent = 0;
278 80ad7816 Alexander Graf
279 80ad7816 Alexander Graf
    if (!basename) {
280 bff39b63 Stefan Weil
        g_free(dupname);
281 80ad7816 Alexander Graf
        return -1;
282 80ad7816 Alexander Graf
    }
283 80ad7816 Alexander Graf
284 80ad7816 Alexander Graf
    basename[0] = '\0';
285 80ad7816 Alexander Graf
    basename++;
286 80ad7816 Alexander Graf
287 c640d088 Alexander Graf
    if (dupname[0]) {
288 c640d088 Alexander Graf
        parent = findnode_nofail(fdt, dupname);
289 c640d088 Alexander Graf
    }
290 c640d088 Alexander Graf
291 c640d088 Alexander Graf
    retval = fdt_add_subnode(fdt, parent, basename);
292 ccbcfedd Alexander Graf
    if (retval < 0) {
293 ccbcfedd Alexander Graf
        fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name,
294 ccbcfedd Alexander Graf
                fdt_strerror(retval));
295 ccbcfedd Alexander Graf
        exit(1);
296 80ad7816 Alexander Graf
    }
297 80ad7816 Alexander Graf
298 80ad7816 Alexander Graf
    g_free(dupname);
299 80ad7816 Alexander Graf
    return retval;
300 80ad7816 Alexander Graf
}
301 71193433 Alexander Graf
302 71193433 Alexander Graf
void qemu_devtree_dumpdtb(void *fdt, int size)
303 71193433 Alexander Graf
{
304 2ff3de68 Markus Armbruster
    const char *dumpdtb = qemu_opt_get(qemu_get_machine_opts(), "dumpdtb");
305 71193433 Alexander Graf
306 2ff3de68 Markus Armbruster
    if (dumpdtb) {
307 2ff3de68 Markus Armbruster
        /* Dump the dtb to a file and quit */
308 2ff3de68 Markus Armbruster
        exit(g_file_set_contents(dumpdtb, fdt, size, NULL) ? 0 : 1);
309 2ff3de68 Markus Armbruster
    }
310 71193433 Alexander Graf
}
311 97c38f8c Peter Maydell
312 97c38f8c Peter Maydell
int qemu_devtree_setprop_sized_cells_from_array(void *fdt,
313 97c38f8c Peter Maydell
                                                const char *node_path,
314 97c38f8c Peter Maydell
                                                const char *property,
315 97c38f8c Peter Maydell
                                                int numvalues,
316 97c38f8c Peter Maydell
                                                uint64_t *values)
317 97c38f8c Peter Maydell
{
318 97c38f8c Peter Maydell
    uint32_t *propcells;
319 97c38f8c Peter Maydell
    uint64_t value;
320 97c38f8c Peter Maydell
    int cellnum, vnum, ncells;
321 97c38f8c Peter Maydell
    uint32_t hival;
322 97c38f8c Peter Maydell
323 97c38f8c Peter Maydell
    propcells = g_new0(uint32_t, numvalues * 2);
324 97c38f8c Peter Maydell
325 97c38f8c Peter Maydell
    cellnum = 0;
326 97c38f8c Peter Maydell
    for (vnum = 0; vnum < numvalues; vnum++) {
327 97c38f8c Peter Maydell
        ncells = values[vnum * 2];
328 97c38f8c Peter Maydell
        if (ncells != 1 && ncells != 2) {
329 97c38f8c Peter Maydell
            return -1;
330 97c38f8c Peter Maydell
        }
331 97c38f8c Peter Maydell
        value = values[vnum * 2 + 1];
332 97c38f8c Peter Maydell
        hival = cpu_to_be32(value >> 32);
333 97c38f8c Peter Maydell
        if (ncells > 1) {
334 97c38f8c Peter Maydell
            propcells[cellnum++] = hival;
335 97c38f8c Peter Maydell
        } else if (hival != 0) {
336 97c38f8c Peter Maydell
            return -1;
337 97c38f8c Peter Maydell
        }
338 97c38f8c Peter Maydell
        propcells[cellnum++] = cpu_to_be32(value);
339 97c38f8c Peter Maydell
    }
340 97c38f8c Peter Maydell
341 97c38f8c Peter Maydell
    return qemu_devtree_setprop(fdt, node_path, property, propcells,
342 97c38f8c Peter Maydell
                                cellnum * sizeof(uint32_t));
343 97c38f8c Peter Maydell
}