]> Git Repo - qemu.git/blob - device_tree.c
Merge remote-tracking branch 'spice/spice.v58' into staging
[qemu.git] / device_tree.c
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 <[email protected]>
8  *          Hollis Blanchard <[email protected]>
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, const 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 }
This page took 0.041269 seconds and 4 git commands to generate.