Statistics
| Branch: | Revision:

root / device_tree.c @ 4b1b1c89

History | View | Annotate | Download (6.6 kB)

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
#include "qemu-option.h"
26
#include "qemu-config.h"
27

    
28
#include <libfdt.h>
29

    
30
#define FDT_MAX_SIZE  0x10000
31

    
32
void *create_device_tree(int *sizep)
33
{
34
    void *fdt;
35
    int ret;
36

    
37
    *sizep = FDT_MAX_SIZE;
38
    fdt = g_malloc0(FDT_MAX_SIZE);
39
    ret = fdt_create(fdt, FDT_MAX_SIZE);
40
    if (ret < 0) {
41
        goto fail;
42
    }
43
    ret = fdt_begin_node(fdt, "");
44
    if (ret < 0) {
45
        goto fail;
46
    }
47
    ret = fdt_end_node(fdt);
48
    if (ret < 0) {
49
        goto fail;
50
    }
51
    ret = fdt_finish(fdt);
52
    if (ret < 0) {
53
        goto fail;
54
    }
55
    ret = fdt_open_into(fdt, fdt, *sizep);
56
    if (ret) {
57
        fprintf(stderr, "Unable to copy device tree in memory\n");
58
        exit(1);
59
    }
60

    
61
    return fdt;
62
fail:
63
    fprintf(stderr, "%s Couldn't create dt: %s\n", __func__, fdt_strerror(ret));
64
    exit(1);
65
}
66

    
67
void *load_device_tree(const char *filename_path, int *sizep)
68
{
69
    int dt_size;
70
    int dt_file_load_size;
71
    int ret;
72
    void *fdt = NULL;
73

    
74
    *sizep = 0;
75
    dt_size = get_image_size(filename_path);
76
    if (dt_size < 0) {
77
        printf("Unable to get size of device tree file '%s'\n",
78
            filename_path);
79
        goto fail;
80
    }
81

    
82
    /* Expand to 2x size to give enough room for manipulation.  */
83
    dt_size += 10000;
84
    dt_size *= 2;
85
    /* First allocate space in qemu for device tree */
86
    fdt = g_malloc0(dt_size);
87

    
88
    dt_file_load_size = load_image(filename_path, fdt);
89
    if (dt_file_load_size < 0) {
90
        printf("Unable to open device tree file '%s'\n",
91
               filename_path);
92
        goto fail;
93
    }
94

    
95
    ret = fdt_open_into(fdt, fdt, dt_size);
96
    if (ret) {
97
        printf("Unable to copy device tree in memory\n");
98
        goto fail;
99
    }
100

    
101
    /* Check sanity of device tree */
102
    if (fdt_check_header(fdt)) {
103
        printf ("Device tree file loaded into memory is invalid: %s\n",
104
            filename_path);
105
        goto fail;
106
    }
107
    *sizep = dt_size;
108
    return fdt;
109

    
110
fail:
111
    g_free(fdt);
112
    return NULL;
113
}
114

    
115
static int findnode_nofail(void *fdt, const char *node_path)
116
{
117
    int offset;
118

    
119
    offset = fdt_path_offset(fdt, node_path);
120
    if (offset < 0) {
121
        fprintf(stderr, "%s Couldn't find node %s: %s\n", __func__, node_path,
122
                fdt_strerror(offset));
123
        exit(1);
124
    }
125

    
126
    return offset;
127
}
128

    
129
int qemu_devtree_setprop(void *fdt, const char *node_path,
130
                         const char *property, void *val_array, int size)
131
{
132
    int r;
133

    
134
    r = fdt_setprop(fdt, findnode_nofail(fdt, node_path), property, val_array, size);
135
    if (r < 0) {
136
        fprintf(stderr, "%s: Couldn't set %s/%s: %s\n", __func__, node_path,
137
                property, fdt_strerror(r));
138
        exit(1);
139
    }
140

    
141
    return r;
142
}
143

    
144
int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
145
                              const char *property, uint32_t val)
146
{
147
    int r;
148

    
149
    r = fdt_setprop_cell(fdt, findnode_nofail(fdt, node_path), property, val);
150
    if (r < 0) {
151
        fprintf(stderr, "%s: Couldn't set %s/%s = %#08x: %s\n", __func__,
152
                node_path, property, val, fdt_strerror(r));
153
        exit(1);
154
    }
155

    
156
    return r;
157
}
158

    
159
int qemu_devtree_setprop_u64(void *fdt, const char *node_path,
160
                             const char *property, uint64_t val)
161
{
162
    val = cpu_to_be64(val);
163
    return qemu_devtree_setprop(fdt, node_path, property, &val, sizeof(val));
164
}
165

    
166
int qemu_devtree_setprop_string(void *fdt, const char *node_path,
167
                                const char *property, const char *string)
168
{
169
    int r;
170

    
171
    r = fdt_setprop_string(fdt, findnode_nofail(fdt, node_path), property, string);
172
    if (r < 0) {
173
        fprintf(stderr, "%s: Couldn't set %s/%s = %s: %s\n", __func__,
174
                node_path, property, string, fdt_strerror(r));
175
        exit(1);
176
    }
177

    
178
    return r;
179
}
180

    
181
uint32_t qemu_devtree_get_phandle(void *fdt, const char *path)
182
{
183
    uint32_t r;
184

    
185
    r = fdt_get_phandle(fdt, findnode_nofail(fdt, path));
186
    if (r <= 0) {
187
        fprintf(stderr, "%s: Couldn't get phandle for %s: %s\n", __func__,
188
                path, fdt_strerror(r));
189
        exit(1);
190
    }
191

    
192
    return r;
193
}
194

    
195
int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
196
                                 const char *property,
197
                                 const char *target_node_path)
198
{
199
    uint32_t phandle = qemu_devtree_get_phandle(fdt, target_node_path);
200
    return qemu_devtree_setprop_cell(fdt, node_path, property, phandle);
201
}
202

    
203
uint32_t qemu_devtree_alloc_phandle(void *fdt)
204
{
205
    static int phandle = 0x0;
206

    
207
    /*
208
     * We need to find out if the user gave us special instruction at
209
     * which phandle id to start allocting phandles.
210
     */
211
    if (!phandle) {
212
        QemuOpts *machine_opts;
213
        machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
214
        if (machine_opts) {
215
            const char *phandle_start;
216
            phandle_start = qemu_opt_get(machine_opts, "phandle_start");
217
            if (phandle_start) {
218
                phandle = strtoul(phandle_start, NULL, 0);
219
            }
220
        }
221
    }
222

    
223
    if (!phandle) {
224
        /*
225
         * None or invalid phandle given on the command line, so fall back to
226
         * default starting point.
227
         */
228
        phandle = 0x8000;
229
    }
230

    
231
    return phandle++;
232
}
233

    
234
int qemu_devtree_nop_node(void *fdt, const char *node_path)
235
{
236
    int r;
237

    
238
    r = fdt_nop_node(fdt, findnode_nofail(fdt, node_path));
239
    if (r < 0) {
240
        fprintf(stderr, "%s: Couldn't nop node %s: %s\n", __func__, node_path,
241
                fdt_strerror(r));
242
        exit(1);
243
    }
244

    
245
    return r;
246
}
247

    
248
int qemu_devtree_add_subnode(void *fdt, const char *name)
249
{
250
    char *dupname = g_strdup(name);
251
    char *basename = strrchr(dupname, '/');
252
    int retval;
253
    int parent = 0;
254

    
255
    if (!basename) {
256
        g_free(dupname);
257
        return -1;
258
    }
259

    
260
    basename[0] = '\0';
261
    basename++;
262

    
263
    if (dupname[0]) {
264
        parent = findnode_nofail(fdt, dupname);
265
    }
266

    
267
    retval = fdt_add_subnode(fdt, parent, basename);
268
    if (retval < 0) {
269
        fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name,
270
                fdt_strerror(retval));
271
        exit(1);
272
    }
273

    
274
    g_free(dupname);
275
    return retval;
276
}