Statistics
| Branch: | Revision:

root / device_tree.c @ 8c43a6f0

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