fdt_overlay.c revision 1.1.1.1.12.1 1 1.1 skrll /* $NetBSD: fdt_overlay.c,v 1.1.1.1.12.1 2020/04/08 14:08:28 martin Exp $ */
2 1.1 skrll
3 1.1.1.1.12.1 martin // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
4 1.1.1.1.12.1 martin /*
5 1.1.1.1.12.1 martin * libfdt - Flat Device Tree manipulation
6 1.1.1.1.12.1 martin * Copyright (C) 2016 Free Electrons
7 1.1.1.1.12.1 martin * Copyright (C) 2016 NextThing Co.
8 1.1.1.1.12.1 martin */
9 1.1 skrll #include "libfdt_env.h"
10 1.1 skrll
11 1.1 skrll #include <fdt.h>
12 1.1 skrll #include <libfdt.h>
13 1.1 skrll
14 1.1 skrll #include "libfdt_internal.h"
15 1.1 skrll
16 1.1 skrll /**
17 1.1 skrll * overlay_get_target_phandle - retrieves the target phandle of a fragment
18 1.1 skrll * @fdto: pointer to the device tree overlay blob
19 1.1 skrll * @fragment: node offset of the fragment in the overlay
20 1.1 skrll *
21 1.1 skrll * overlay_get_target_phandle() retrieves the target phandle of an
22 1.1 skrll * overlay fragment when that fragment uses a phandle (target
23 1.1 skrll * property) instead of a path (target-path property).
24 1.1 skrll *
25 1.1 skrll * returns:
26 1.1 skrll * the phandle pointed by the target property
27 1.1 skrll * 0, if the phandle was not found
28 1.1 skrll * -1, if the phandle was malformed
29 1.1 skrll */
30 1.1 skrll static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
31 1.1 skrll {
32 1.1 skrll const fdt32_t *val;
33 1.1 skrll int len;
34 1.1 skrll
35 1.1 skrll val = fdt_getprop(fdto, fragment, "target", &len);
36 1.1 skrll if (!val)
37 1.1 skrll return 0;
38 1.1 skrll
39 1.1 skrll if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
40 1.1 skrll return (uint32_t)-1;
41 1.1 skrll
42 1.1 skrll return fdt32_to_cpu(*val);
43 1.1 skrll }
44 1.1 skrll
45 1.1 skrll /**
46 1.1 skrll * overlay_get_target - retrieves the offset of a fragment's target
47 1.1 skrll * @fdt: Base device tree blob
48 1.1 skrll * @fdto: Device tree overlay blob
49 1.1 skrll * @fragment: node offset of the fragment in the overlay
50 1.1.1.1.12.1 martin * @pathp: pointer which receives the path of the target (or NULL)
51 1.1 skrll *
52 1.1 skrll * overlay_get_target() retrieves the target offset in the base
53 1.1.1.1.12.1 martin * device tree of a fragment, no matter how the actual targeting is
54 1.1 skrll * done (through a phandle or a path)
55 1.1 skrll *
56 1.1 skrll * returns:
57 1.1.1.1.12.1 martin * the targeted node offset in the base device tree
58 1.1 skrll * Negative error code on error
59 1.1 skrll */
60 1.1 skrll static int overlay_get_target(const void *fdt, const void *fdto,
61 1.1.1.1.12.1 martin int fragment, char const **pathp)
62 1.1 skrll {
63 1.1 skrll uint32_t phandle;
64 1.1.1.1.12.1 martin const char *path = NULL;
65 1.1.1.1.12.1 martin int path_len = 0, ret;
66 1.1 skrll
67 1.1 skrll /* Try first to do a phandle based lookup */
68 1.1 skrll phandle = overlay_get_target_phandle(fdto, fragment);
69 1.1 skrll if (phandle == (uint32_t)-1)
70 1.1 skrll return -FDT_ERR_BADPHANDLE;
71 1.1 skrll
72 1.1.1.1.12.1 martin /* no phandle, try path */
73 1.1.1.1.12.1 martin if (!phandle) {
74 1.1.1.1.12.1 martin /* And then a path based lookup */
75 1.1.1.1.12.1 martin path = fdt_getprop(fdto, fragment, "target-path", &path_len);
76 1.1.1.1.12.1 martin if (path)
77 1.1.1.1.12.1 martin ret = fdt_path_offset(fdt, path);
78 1.1.1.1.12.1 martin else
79 1.1.1.1.12.1 martin ret = path_len;
80 1.1.1.1.12.1 martin } else
81 1.1.1.1.12.1 martin ret = fdt_node_offset_by_phandle(fdt, phandle);
82 1.1 skrll
83 1.1.1.1.12.1 martin /*
84 1.1.1.1.12.1 martin * If we haven't found either a target or a
85 1.1.1.1.12.1 martin * target-path property in a node that contains a
86 1.1.1.1.12.1 martin * __overlay__ subnode (we wouldn't be called
87 1.1.1.1.12.1 martin * otherwise), consider it a improperly written
88 1.1.1.1.12.1 martin * overlay
89 1.1.1.1.12.1 martin */
90 1.1.1.1.12.1 martin if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
91 1.1.1.1.12.1 martin ret = -FDT_ERR_BADOVERLAY;
92 1.1 skrll
93 1.1.1.1.12.1 martin /* return on error */
94 1.1.1.1.12.1 martin if (ret < 0)
95 1.1.1.1.12.1 martin return ret;
96 1.1.1.1.12.1 martin
97 1.1.1.1.12.1 martin /* return pointer to path (if available) */
98 1.1.1.1.12.1 martin if (pathp)
99 1.1.1.1.12.1 martin *pathp = path ? path : NULL;
100 1.1 skrll
101 1.1.1.1.12.1 martin return ret;
102 1.1 skrll }
103 1.1 skrll
104 1.1 skrll /**
105 1.1 skrll * overlay_phandle_add_offset - Increases a phandle by an offset
106 1.1 skrll * @fdt: Base device tree blob
107 1.1 skrll * @node: Device tree overlay blob
108 1.1 skrll * @name: Name of the property to modify (phandle or linux,phandle)
109 1.1 skrll * @delta: offset to apply
110 1.1 skrll *
111 1.1 skrll * overlay_phandle_add_offset() increments a node phandle by a given
112 1.1 skrll * offset.
113 1.1 skrll *
114 1.1 skrll * returns:
115 1.1 skrll * 0 on success.
116 1.1 skrll * Negative error code on error
117 1.1 skrll */
118 1.1 skrll static int overlay_phandle_add_offset(void *fdt, int node,
119 1.1 skrll const char *name, uint32_t delta)
120 1.1 skrll {
121 1.1 skrll const fdt32_t *val;
122 1.1 skrll uint32_t adj_val;
123 1.1 skrll int len;
124 1.1 skrll
125 1.1 skrll val = fdt_getprop(fdt, node, name, &len);
126 1.1 skrll if (!val)
127 1.1 skrll return len;
128 1.1 skrll
129 1.1 skrll if (len != sizeof(*val))
130 1.1 skrll return -FDT_ERR_BADPHANDLE;
131 1.1 skrll
132 1.1 skrll adj_val = fdt32_to_cpu(*val);
133 1.1 skrll if ((adj_val + delta) < adj_val)
134 1.1 skrll return -FDT_ERR_NOPHANDLES;
135 1.1 skrll
136 1.1 skrll adj_val += delta;
137 1.1 skrll if (adj_val == (uint32_t)-1)
138 1.1 skrll return -FDT_ERR_NOPHANDLES;
139 1.1 skrll
140 1.1 skrll return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
141 1.1 skrll }
142 1.1 skrll
143 1.1 skrll /**
144 1.1 skrll * overlay_adjust_node_phandles - Offsets the phandles of a node
145 1.1 skrll * @fdto: Device tree overlay blob
146 1.1 skrll * @node: Offset of the node we want to adjust
147 1.1 skrll * @delta: Offset to shift the phandles of
148 1.1 skrll *
149 1.1 skrll * overlay_adjust_node_phandles() adds a constant to all the phandles
150 1.1 skrll * of a given node. This is mainly use as part of the overlay
151 1.1 skrll * application process, when we want to update all the overlay
152 1.1 skrll * phandles to not conflict with the overlays of the base device tree.
153 1.1 skrll *
154 1.1 skrll * returns:
155 1.1 skrll * 0 on success
156 1.1 skrll * Negative error code on failure
157 1.1 skrll */
158 1.1 skrll static int overlay_adjust_node_phandles(void *fdto, int node,
159 1.1 skrll uint32_t delta)
160 1.1 skrll {
161 1.1 skrll int child;
162 1.1 skrll int ret;
163 1.1 skrll
164 1.1 skrll ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
165 1.1 skrll if (ret && ret != -FDT_ERR_NOTFOUND)
166 1.1 skrll return ret;
167 1.1 skrll
168 1.1 skrll ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
169 1.1 skrll if (ret && ret != -FDT_ERR_NOTFOUND)
170 1.1 skrll return ret;
171 1.1 skrll
172 1.1 skrll fdt_for_each_subnode(child, fdto, node) {
173 1.1 skrll ret = overlay_adjust_node_phandles(fdto, child, delta);
174 1.1 skrll if (ret)
175 1.1 skrll return ret;
176 1.1 skrll }
177 1.1 skrll
178 1.1 skrll return 0;
179 1.1 skrll }
180 1.1 skrll
181 1.1 skrll /**
182 1.1 skrll * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
183 1.1 skrll * @fdto: Device tree overlay blob
184 1.1 skrll * @delta: Offset to shift the phandles of
185 1.1 skrll *
186 1.1 skrll * overlay_adjust_local_phandles() adds a constant to all the
187 1.1 skrll * phandles of an overlay. This is mainly use as part of the overlay
188 1.1 skrll * application process, when we want to update all the overlay
189 1.1 skrll * phandles to not conflict with the overlays of the base device tree.
190 1.1 skrll *
191 1.1 skrll * returns:
192 1.1 skrll * 0 on success
193 1.1 skrll * Negative error code on failure
194 1.1 skrll */
195 1.1 skrll static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
196 1.1 skrll {
197 1.1 skrll /*
198 1.1 skrll * Start adjusting the phandles from the overlay root
199 1.1 skrll */
200 1.1 skrll return overlay_adjust_node_phandles(fdto, 0, delta);
201 1.1 skrll }
202 1.1 skrll
203 1.1 skrll /**
204 1.1 skrll * overlay_update_local_node_references - Adjust the overlay references
205 1.1 skrll * @fdto: Device tree overlay blob
206 1.1 skrll * @tree_node: Node offset of the node to operate on
207 1.1 skrll * @fixup_node: Node offset of the matching local fixups node
208 1.1 skrll * @delta: Offset to shift the phandles of
209 1.1 skrll *
210 1.1 skrll * overlay_update_local_nodes_references() update the phandles
211 1.1 skrll * pointing to a node within the device tree overlay by adding a
212 1.1 skrll * constant delta.
213 1.1 skrll *
214 1.1 skrll * This is mainly used as part of a device tree application process,
215 1.1 skrll * where you want the device tree overlays phandles to not conflict
216 1.1 skrll * with the ones from the base device tree before merging them.
217 1.1 skrll *
218 1.1 skrll * returns:
219 1.1 skrll * 0 on success
220 1.1 skrll * Negative error code on failure
221 1.1 skrll */
222 1.1 skrll static int overlay_update_local_node_references(void *fdto,
223 1.1 skrll int tree_node,
224 1.1 skrll int fixup_node,
225 1.1 skrll uint32_t delta)
226 1.1 skrll {
227 1.1 skrll int fixup_prop;
228 1.1 skrll int fixup_child;
229 1.1 skrll int ret;
230 1.1 skrll
231 1.1 skrll fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
232 1.1 skrll const fdt32_t *fixup_val;
233 1.1 skrll const char *tree_val;
234 1.1 skrll const char *name;
235 1.1 skrll int fixup_len;
236 1.1 skrll int tree_len;
237 1.1 skrll int i;
238 1.1 skrll
239 1.1 skrll fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
240 1.1 skrll &name, &fixup_len);
241 1.1 skrll if (!fixup_val)
242 1.1 skrll return fixup_len;
243 1.1 skrll
244 1.1 skrll if (fixup_len % sizeof(uint32_t))
245 1.1 skrll return -FDT_ERR_BADOVERLAY;
246 1.1 skrll
247 1.1 skrll tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
248 1.1 skrll if (!tree_val) {
249 1.1 skrll if (tree_len == -FDT_ERR_NOTFOUND)
250 1.1 skrll return -FDT_ERR_BADOVERLAY;
251 1.1 skrll
252 1.1 skrll return tree_len;
253 1.1 skrll }
254 1.1 skrll
255 1.1 skrll for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
256 1.1 skrll fdt32_t adj_val;
257 1.1 skrll uint32_t poffset;
258 1.1 skrll
259 1.1 skrll poffset = fdt32_to_cpu(fixup_val[i]);
260 1.1 skrll
261 1.1 skrll /*
262 1.1 skrll * phandles to fixup can be unaligned.
263 1.1 skrll *
264 1.1 skrll * Use a memcpy for the architectures that do
265 1.1 skrll * not support unaligned accesses.
266 1.1 skrll */
267 1.1 skrll memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
268 1.1 skrll
269 1.1 skrll adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
270 1.1 skrll
271 1.1 skrll ret = fdt_setprop_inplace_namelen_partial(fdto,
272 1.1 skrll tree_node,
273 1.1 skrll name,
274 1.1 skrll strlen(name),
275 1.1 skrll poffset,
276 1.1 skrll &adj_val,
277 1.1 skrll sizeof(adj_val));
278 1.1 skrll if (ret == -FDT_ERR_NOSPACE)
279 1.1 skrll return -FDT_ERR_BADOVERLAY;
280 1.1 skrll
281 1.1 skrll if (ret)
282 1.1 skrll return ret;
283 1.1 skrll }
284 1.1 skrll }
285 1.1 skrll
286 1.1 skrll fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
287 1.1 skrll const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
288 1.1 skrll NULL);
289 1.1 skrll int tree_child;
290 1.1 skrll
291 1.1 skrll tree_child = fdt_subnode_offset(fdto, tree_node,
292 1.1 skrll fixup_child_name);
293 1.1 skrll if (tree_child == -FDT_ERR_NOTFOUND)
294 1.1 skrll return -FDT_ERR_BADOVERLAY;
295 1.1 skrll if (tree_child < 0)
296 1.1 skrll return tree_child;
297 1.1 skrll
298 1.1 skrll ret = overlay_update_local_node_references(fdto,
299 1.1 skrll tree_child,
300 1.1 skrll fixup_child,
301 1.1 skrll delta);
302 1.1 skrll if (ret)
303 1.1 skrll return ret;
304 1.1 skrll }
305 1.1 skrll
306 1.1 skrll return 0;
307 1.1 skrll }
308 1.1 skrll
309 1.1 skrll /**
310 1.1 skrll * overlay_update_local_references - Adjust the overlay references
311 1.1 skrll * @fdto: Device tree overlay blob
312 1.1 skrll * @delta: Offset to shift the phandles of
313 1.1 skrll *
314 1.1 skrll * overlay_update_local_references() update all the phandles pointing
315 1.1 skrll * to a node within the device tree overlay by adding a constant
316 1.1 skrll * delta to not conflict with the base overlay.
317 1.1 skrll *
318 1.1 skrll * This is mainly used as part of a device tree application process,
319 1.1 skrll * where you want the device tree overlays phandles to not conflict
320 1.1 skrll * with the ones from the base device tree before merging them.
321 1.1 skrll *
322 1.1 skrll * returns:
323 1.1 skrll * 0 on success
324 1.1 skrll * Negative error code on failure
325 1.1 skrll */
326 1.1 skrll static int overlay_update_local_references(void *fdto, uint32_t delta)
327 1.1 skrll {
328 1.1 skrll int fixups;
329 1.1 skrll
330 1.1 skrll fixups = fdt_path_offset(fdto, "/__local_fixups__");
331 1.1 skrll if (fixups < 0) {
332 1.1 skrll /* There's no local phandles to adjust, bail out */
333 1.1 skrll if (fixups == -FDT_ERR_NOTFOUND)
334 1.1 skrll return 0;
335 1.1 skrll
336 1.1 skrll return fixups;
337 1.1 skrll }
338 1.1 skrll
339 1.1 skrll /*
340 1.1 skrll * Update our local references from the root of the tree
341 1.1 skrll */
342 1.1 skrll return overlay_update_local_node_references(fdto, 0, fixups,
343 1.1 skrll delta);
344 1.1 skrll }
345 1.1 skrll
346 1.1 skrll /**
347 1.1 skrll * overlay_fixup_one_phandle - Set an overlay phandle to the base one
348 1.1 skrll * @fdt: Base Device Tree blob
349 1.1 skrll * @fdto: Device tree overlay blob
350 1.1 skrll * @symbols_off: Node offset of the symbols node in the base device tree
351 1.1 skrll * @path: Path to a node holding a phandle in the overlay
352 1.1 skrll * @path_len: number of path characters to consider
353 1.1 skrll * @name: Name of the property holding the phandle reference in the overlay
354 1.1 skrll * @name_len: number of name characters to consider
355 1.1 skrll * @poffset: Offset within the overlay property where the phandle is stored
356 1.1 skrll * @label: Label of the node referenced by the phandle
357 1.1 skrll *
358 1.1 skrll * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
359 1.1 skrll * a node in the base device tree.
360 1.1 skrll *
361 1.1 skrll * This is part of the device tree overlay application process, when
362 1.1 skrll * you want all the phandles in the overlay to point to the actual
363 1.1 skrll * base dt nodes.
364 1.1 skrll *
365 1.1 skrll * returns:
366 1.1 skrll * 0 on success
367 1.1 skrll * Negative error code on failure
368 1.1 skrll */
369 1.1 skrll static int overlay_fixup_one_phandle(void *fdt, void *fdto,
370 1.1 skrll int symbols_off,
371 1.1 skrll const char *path, uint32_t path_len,
372 1.1 skrll const char *name, uint32_t name_len,
373 1.1 skrll int poffset, const char *label)
374 1.1 skrll {
375 1.1 skrll const char *symbol_path;
376 1.1 skrll uint32_t phandle;
377 1.1 skrll fdt32_t phandle_prop;
378 1.1 skrll int symbol_off, fixup_off;
379 1.1 skrll int prop_len;
380 1.1 skrll
381 1.1 skrll if (symbols_off < 0)
382 1.1 skrll return symbols_off;
383 1.1 skrll
384 1.1 skrll symbol_path = fdt_getprop(fdt, symbols_off, label,
385 1.1 skrll &prop_len);
386 1.1 skrll if (!symbol_path)
387 1.1 skrll return prop_len;
388 1.1 skrll
389 1.1 skrll symbol_off = fdt_path_offset(fdt, symbol_path);
390 1.1 skrll if (symbol_off < 0)
391 1.1 skrll return symbol_off;
392 1.1 skrll
393 1.1 skrll phandle = fdt_get_phandle(fdt, symbol_off);
394 1.1 skrll if (!phandle)
395 1.1 skrll return -FDT_ERR_NOTFOUND;
396 1.1 skrll
397 1.1 skrll fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
398 1.1 skrll if (fixup_off == -FDT_ERR_NOTFOUND)
399 1.1 skrll return -FDT_ERR_BADOVERLAY;
400 1.1 skrll if (fixup_off < 0)
401 1.1 skrll return fixup_off;
402 1.1 skrll
403 1.1 skrll phandle_prop = cpu_to_fdt32(phandle);
404 1.1 skrll return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
405 1.1 skrll name, name_len, poffset,
406 1.1 skrll &phandle_prop,
407 1.1 skrll sizeof(phandle_prop));
408 1.1 skrll };
409 1.1 skrll
410 1.1 skrll /**
411 1.1 skrll * overlay_fixup_phandle - Set an overlay phandle to the base one
412 1.1 skrll * @fdt: Base Device Tree blob
413 1.1 skrll * @fdto: Device tree overlay blob
414 1.1 skrll * @symbols_off: Node offset of the symbols node in the base device tree
415 1.1 skrll * @property: Property offset in the overlay holding the list of fixups
416 1.1 skrll *
417 1.1 skrll * overlay_fixup_phandle() resolves all the overlay phandles pointed
418 1.1 skrll * to in a __fixups__ property, and updates them to match the phandles
419 1.1 skrll * in use in the base device tree.
420 1.1 skrll *
421 1.1 skrll * This is part of the device tree overlay application process, when
422 1.1 skrll * you want all the phandles in the overlay to point to the actual
423 1.1 skrll * base dt nodes.
424 1.1 skrll *
425 1.1 skrll * returns:
426 1.1 skrll * 0 on success
427 1.1 skrll * Negative error code on failure
428 1.1 skrll */
429 1.1 skrll static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
430 1.1 skrll int property)
431 1.1 skrll {
432 1.1 skrll const char *value;
433 1.1 skrll const char *label;
434 1.1 skrll int len;
435 1.1 skrll
436 1.1 skrll value = fdt_getprop_by_offset(fdto, property,
437 1.1 skrll &label, &len);
438 1.1 skrll if (!value) {
439 1.1 skrll if (len == -FDT_ERR_NOTFOUND)
440 1.1 skrll return -FDT_ERR_INTERNAL;
441 1.1 skrll
442 1.1 skrll return len;
443 1.1 skrll }
444 1.1 skrll
445 1.1 skrll do {
446 1.1 skrll const char *path, *name, *fixup_end;
447 1.1 skrll const char *fixup_str = value;
448 1.1 skrll uint32_t path_len, name_len;
449 1.1 skrll uint32_t fixup_len;
450 1.1 skrll char *sep, *endptr;
451 1.1 skrll int poffset, ret;
452 1.1 skrll
453 1.1 skrll fixup_end = memchr(value, '\0', len);
454 1.1 skrll if (!fixup_end)
455 1.1 skrll return -FDT_ERR_BADOVERLAY;
456 1.1 skrll fixup_len = fixup_end - fixup_str;
457 1.1 skrll
458 1.1 skrll len -= fixup_len + 1;
459 1.1 skrll value += fixup_len + 1;
460 1.1 skrll
461 1.1 skrll path = fixup_str;
462 1.1 skrll sep = memchr(fixup_str, ':', fixup_len);
463 1.1 skrll if (!sep || *sep != ':')
464 1.1 skrll return -FDT_ERR_BADOVERLAY;
465 1.1 skrll
466 1.1 skrll path_len = sep - path;
467 1.1 skrll if (path_len == (fixup_len - 1))
468 1.1 skrll return -FDT_ERR_BADOVERLAY;
469 1.1 skrll
470 1.1 skrll fixup_len -= path_len + 1;
471 1.1 skrll name = sep + 1;
472 1.1 skrll sep = memchr(name, ':', fixup_len);
473 1.1 skrll if (!sep || *sep != ':')
474 1.1 skrll return -FDT_ERR_BADOVERLAY;
475 1.1 skrll
476 1.1 skrll name_len = sep - name;
477 1.1 skrll if (!name_len)
478 1.1 skrll return -FDT_ERR_BADOVERLAY;
479 1.1 skrll
480 1.1 skrll poffset = strtoul(sep + 1, &endptr, 10);
481 1.1 skrll if ((*endptr != '\0') || (endptr <= (sep + 1)))
482 1.1 skrll return -FDT_ERR_BADOVERLAY;
483 1.1 skrll
484 1.1 skrll ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
485 1.1 skrll path, path_len, name, name_len,
486 1.1 skrll poffset, label);
487 1.1 skrll if (ret)
488 1.1 skrll return ret;
489 1.1 skrll } while (len > 0);
490 1.1 skrll
491 1.1 skrll return 0;
492 1.1 skrll }
493 1.1 skrll
494 1.1 skrll /**
495 1.1 skrll * overlay_fixup_phandles - Resolve the overlay phandles to the base
496 1.1 skrll * device tree
497 1.1 skrll * @fdt: Base Device Tree blob
498 1.1 skrll * @fdto: Device tree overlay blob
499 1.1 skrll *
500 1.1 skrll * overlay_fixup_phandles() resolves all the overlay phandles pointing
501 1.1 skrll * to nodes in the base device tree.
502 1.1 skrll *
503 1.1 skrll * This is one of the steps of the device tree overlay application
504 1.1 skrll * process, when you want all the phandles in the overlay to point to
505 1.1 skrll * the actual base dt nodes.
506 1.1 skrll *
507 1.1 skrll * returns:
508 1.1 skrll * 0 on success
509 1.1 skrll * Negative error code on failure
510 1.1 skrll */
511 1.1 skrll static int overlay_fixup_phandles(void *fdt, void *fdto)
512 1.1 skrll {
513 1.1 skrll int fixups_off, symbols_off;
514 1.1 skrll int property;
515 1.1 skrll
516 1.1 skrll /* We can have overlays without any fixups */
517 1.1 skrll fixups_off = fdt_path_offset(fdto, "/__fixups__");
518 1.1 skrll if (fixups_off == -FDT_ERR_NOTFOUND)
519 1.1 skrll return 0; /* nothing to do */
520 1.1 skrll if (fixups_off < 0)
521 1.1 skrll return fixups_off;
522 1.1 skrll
523 1.1 skrll /* And base DTs without symbols */
524 1.1 skrll symbols_off = fdt_path_offset(fdt, "/__symbols__");
525 1.1 skrll if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
526 1.1 skrll return symbols_off;
527 1.1 skrll
528 1.1 skrll fdt_for_each_property_offset(property, fdto, fixups_off) {
529 1.1 skrll int ret;
530 1.1 skrll
531 1.1 skrll ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
532 1.1 skrll if (ret)
533 1.1 skrll return ret;
534 1.1 skrll }
535 1.1 skrll
536 1.1 skrll return 0;
537 1.1 skrll }
538 1.1 skrll
539 1.1 skrll /**
540 1.1 skrll * overlay_apply_node - Merges a node into the base device tree
541 1.1 skrll * @fdt: Base Device Tree blob
542 1.1 skrll * @target: Node offset in the base device tree to apply the fragment to
543 1.1 skrll * @fdto: Device tree overlay blob
544 1.1 skrll * @node: Node offset in the overlay holding the changes to merge
545 1.1 skrll *
546 1.1 skrll * overlay_apply_node() merges a node into a target base device tree
547 1.1 skrll * node pointed.
548 1.1 skrll *
549 1.1 skrll * This is part of the final step in the device tree overlay
550 1.1 skrll * application process, when all the phandles have been adjusted and
551 1.1 skrll * resolved and you just have to merge overlay into the base device
552 1.1 skrll * tree.
553 1.1 skrll *
554 1.1 skrll * returns:
555 1.1 skrll * 0 on success
556 1.1 skrll * Negative error code on failure
557 1.1 skrll */
558 1.1 skrll static int overlay_apply_node(void *fdt, int target,
559 1.1 skrll void *fdto, int node)
560 1.1 skrll {
561 1.1 skrll int property;
562 1.1 skrll int subnode;
563 1.1 skrll
564 1.1 skrll fdt_for_each_property_offset(property, fdto, node) {
565 1.1 skrll const char *name;
566 1.1 skrll const void *prop;
567 1.1 skrll int prop_len;
568 1.1 skrll int ret;
569 1.1 skrll
570 1.1 skrll prop = fdt_getprop_by_offset(fdto, property, &name,
571 1.1 skrll &prop_len);
572 1.1 skrll if (prop_len == -FDT_ERR_NOTFOUND)
573 1.1 skrll return -FDT_ERR_INTERNAL;
574 1.1 skrll if (prop_len < 0)
575 1.1 skrll return prop_len;
576 1.1 skrll
577 1.1 skrll ret = fdt_setprop(fdt, target, name, prop, prop_len);
578 1.1 skrll if (ret)
579 1.1 skrll return ret;
580 1.1 skrll }
581 1.1 skrll
582 1.1 skrll fdt_for_each_subnode(subnode, fdto, node) {
583 1.1 skrll const char *name = fdt_get_name(fdto, subnode, NULL);
584 1.1 skrll int nnode;
585 1.1 skrll int ret;
586 1.1 skrll
587 1.1 skrll nnode = fdt_add_subnode(fdt, target, name);
588 1.1 skrll if (nnode == -FDT_ERR_EXISTS) {
589 1.1 skrll nnode = fdt_subnode_offset(fdt, target, name);
590 1.1 skrll if (nnode == -FDT_ERR_NOTFOUND)
591 1.1 skrll return -FDT_ERR_INTERNAL;
592 1.1 skrll }
593 1.1 skrll
594 1.1 skrll if (nnode < 0)
595 1.1 skrll return nnode;
596 1.1 skrll
597 1.1 skrll ret = overlay_apply_node(fdt, nnode, fdto, subnode);
598 1.1 skrll if (ret)
599 1.1 skrll return ret;
600 1.1 skrll }
601 1.1 skrll
602 1.1 skrll return 0;
603 1.1 skrll }
604 1.1 skrll
605 1.1 skrll /**
606 1.1 skrll * overlay_merge - Merge an overlay into its base device tree
607 1.1 skrll * @fdt: Base Device Tree blob
608 1.1 skrll * @fdto: Device tree overlay blob
609 1.1 skrll *
610 1.1 skrll * overlay_merge() merges an overlay into its base device tree.
611 1.1 skrll *
612 1.1.1.1.12.1 martin * This is the next to last step in the device tree overlay application
613 1.1 skrll * process, when all the phandles have been adjusted and resolved and
614 1.1 skrll * you just have to merge overlay into the base device tree.
615 1.1 skrll *
616 1.1 skrll * returns:
617 1.1 skrll * 0 on success
618 1.1 skrll * Negative error code on failure
619 1.1 skrll */
620 1.1 skrll static int overlay_merge(void *fdt, void *fdto)
621 1.1 skrll {
622 1.1 skrll int fragment;
623 1.1 skrll
624 1.1 skrll fdt_for_each_subnode(fragment, fdto, 0) {
625 1.1 skrll int overlay;
626 1.1 skrll int target;
627 1.1 skrll int ret;
628 1.1 skrll
629 1.1 skrll /*
630 1.1 skrll * Each fragments will have an __overlay__ node. If
631 1.1 skrll * they don't, it's not supposed to be merged
632 1.1 skrll */
633 1.1 skrll overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
634 1.1 skrll if (overlay == -FDT_ERR_NOTFOUND)
635 1.1 skrll continue;
636 1.1 skrll
637 1.1 skrll if (overlay < 0)
638 1.1 skrll return overlay;
639 1.1 skrll
640 1.1.1.1.12.1 martin target = overlay_get_target(fdt, fdto, fragment, NULL);
641 1.1 skrll if (target < 0)
642 1.1 skrll return target;
643 1.1 skrll
644 1.1 skrll ret = overlay_apply_node(fdt, target, fdto, overlay);
645 1.1 skrll if (ret)
646 1.1 skrll return ret;
647 1.1 skrll }
648 1.1 skrll
649 1.1 skrll return 0;
650 1.1 skrll }
651 1.1 skrll
652 1.1.1.1.12.1 martin static int get_path_len(const void *fdt, int nodeoffset)
653 1.1.1.1.12.1 martin {
654 1.1.1.1.12.1 martin int len = 0, namelen;
655 1.1.1.1.12.1 martin const char *name;
656 1.1.1.1.12.1 martin
657 1.1.1.1.12.1 martin FDT_RO_PROBE(fdt);
658 1.1.1.1.12.1 martin
659 1.1.1.1.12.1 martin for (;;) {
660 1.1.1.1.12.1 martin name = fdt_get_name(fdt, nodeoffset, &namelen);
661 1.1.1.1.12.1 martin if (!name)
662 1.1.1.1.12.1 martin return namelen;
663 1.1.1.1.12.1 martin
664 1.1.1.1.12.1 martin /* root? we're done */
665 1.1.1.1.12.1 martin if (namelen == 0)
666 1.1.1.1.12.1 martin break;
667 1.1.1.1.12.1 martin
668 1.1.1.1.12.1 martin nodeoffset = fdt_parent_offset(fdt, nodeoffset);
669 1.1.1.1.12.1 martin if (nodeoffset < 0)
670 1.1.1.1.12.1 martin return nodeoffset;
671 1.1.1.1.12.1 martin len += namelen + 1;
672 1.1.1.1.12.1 martin }
673 1.1.1.1.12.1 martin
674 1.1.1.1.12.1 martin /* in case of root pretend it's "/" */
675 1.1.1.1.12.1 martin if (len == 0)
676 1.1.1.1.12.1 martin len++;
677 1.1.1.1.12.1 martin return len;
678 1.1.1.1.12.1 martin }
679 1.1.1.1.12.1 martin
680 1.1.1.1.12.1 martin /**
681 1.1.1.1.12.1 martin * overlay_symbol_update - Update the symbols of base tree after a merge
682 1.1.1.1.12.1 martin * @fdt: Base Device Tree blob
683 1.1.1.1.12.1 martin * @fdto: Device tree overlay blob
684 1.1.1.1.12.1 martin *
685 1.1.1.1.12.1 martin * overlay_symbol_update() updates the symbols of the base tree with the
686 1.1.1.1.12.1 martin * symbols of the applied overlay
687 1.1.1.1.12.1 martin *
688 1.1.1.1.12.1 martin * This is the last step in the device tree overlay application
689 1.1.1.1.12.1 martin * process, allowing the reference of overlay symbols by subsequent
690 1.1.1.1.12.1 martin * overlay operations.
691 1.1.1.1.12.1 martin *
692 1.1.1.1.12.1 martin * returns:
693 1.1.1.1.12.1 martin * 0 on success
694 1.1.1.1.12.1 martin * Negative error code on failure
695 1.1.1.1.12.1 martin */
696 1.1.1.1.12.1 martin static int overlay_symbol_update(void *fdt, void *fdto)
697 1.1.1.1.12.1 martin {
698 1.1.1.1.12.1 martin int root_sym, ov_sym, prop, path_len, fragment, target;
699 1.1.1.1.12.1 martin int len, frag_name_len, ret, rel_path_len;
700 1.1.1.1.12.1 martin const char *s, *e;
701 1.1.1.1.12.1 martin const char *path;
702 1.1.1.1.12.1 martin const char *name;
703 1.1.1.1.12.1 martin const char *frag_name;
704 1.1.1.1.12.1 martin const char *rel_path;
705 1.1.1.1.12.1 martin const char *target_path;
706 1.1.1.1.12.1 martin char *buf;
707 1.1.1.1.12.1 martin void *p;
708 1.1.1.1.12.1 martin
709 1.1.1.1.12.1 martin ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
710 1.1.1.1.12.1 martin
711 1.1.1.1.12.1 martin /* if no overlay symbols exist no problem */
712 1.1.1.1.12.1 martin if (ov_sym < 0)
713 1.1.1.1.12.1 martin return 0;
714 1.1.1.1.12.1 martin
715 1.1.1.1.12.1 martin root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
716 1.1.1.1.12.1 martin
717 1.1.1.1.12.1 martin /* it no root symbols exist we should create them */
718 1.1.1.1.12.1 martin if (root_sym == -FDT_ERR_NOTFOUND)
719 1.1.1.1.12.1 martin root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
720 1.1.1.1.12.1 martin
721 1.1.1.1.12.1 martin /* any error is fatal now */
722 1.1.1.1.12.1 martin if (root_sym < 0)
723 1.1.1.1.12.1 martin return root_sym;
724 1.1.1.1.12.1 martin
725 1.1.1.1.12.1 martin /* iterate over each overlay symbol */
726 1.1.1.1.12.1 martin fdt_for_each_property_offset(prop, fdto, ov_sym) {
727 1.1.1.1.12.1 martin path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
728 1.1.1.1.12.1 martin if (!path)
729 1.1.1.1.12.1 martin return path_len;
730 1.1.1.1.12.1 martin
731 1.1.1.1.12.1 martin /* verify it's a string property (terminated by a single \0) */
732 1.1.1.1.12.1 martin if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
733 1.1.1.1.12.1 martin return -FDT_ERR_BADVALUE;
734 1.1.1.1.12.1 martin
735 1.1.1.1.12.1 martin /* keep end marker to avoid strlen() */
736 1.1.1.1.12.1 martin e = path + path_len;
737 1.1.1.1.12.1 martin
738 1.1.1.1.12.1 martin if (*path != '/')
739 1.1.1.1.12.1 martin return -FDT_ERR_BADVALUE;
740 1.1.1.1.12.1 martin
741 1.1.1.1.12.1 martin /* get fragment name first */
742 1.1.1.1.12.1 martin s = strchr(path + 1, '/');
743 1.1.1.1.12.1 martin if (!s) {
744 1.1.1.1.12.1 martin /* Symbol refers to something that won't end
745 1.1.1.1.12.1 martin * up in the target tree */
746 1.1.1.1.12.1 martin continue;
747 1.1.1.1.12.1 martin }
748 1.1.1.1.12.1 martin
749 1.1.1.1.12.1 martin frag_name = path + 1;
750 1.1.1.1.12.1 martin frag_name_len = s - path - 1;
751 1.1.1.1.12.1 martin
752 1.1.1.1.12.1 martin /* verify format; safe since "s" lies in \0 terminated prop */
753 1.1.1.1.12.1 martin len = sizeof("/__overlay__/") - 1;
754 1.1.1.1.12.1 martin if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
755 1.1.1.1.12.1 martin /* /<fragment-name>/__overlay__/<relative-subnode-path> */
756 1.1.1.1.12.1 martin rel_path = s + len;
757 1.1.1.1.12.1 martin rel_path_len = e - rel_path;
758 1.1.1.1.12.1 martin } else if ((e - s) == len
759 1.1.1.1.12.1 martin && (memcmp(s, "/__overlay__", len - 1) == 0)) {
760 1.1.1.1.12.1 martin /* /<fragment-name>/__overlay__ */
761 1.1.1.1.12.1 martin rel_path = "";
762 1.1.1.1.12.1 martin rel_path_len = 0;
763 1.1.1.1.12.1 martin } else {
764 1.1.1.1.12.1 martin /* Symbol refers to something that won't end
765 1.1.1.1.12.1 martin * up in the target tree */
766 1.1.1.1.12.1 martin continue;
767 1.1.1.1.12.1 martin }
768 1.1.1.1.12.1 martin
769 1.1.1.1.12.1 martin /* find the fragment index in which the symbol lies */
770 1.1.1.1.12.1 martin ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
771 1.1.1.1.12.1 martin frag_name_len);
772 1.1.1.1.12.1 martin /* not found? */
773 1.1.1.1.12.1 martin if (ret < 0)
774 1.1.1.1.12.1 martin return -FDT_ERR_BADOVERLAY;
775 1.1.1.1.12.1 martin fragment = ret;
776 1.1.1.1.12.1 martin
777 1.1.1.1.12.1 martin /* an __overlay__ subnode must exist */
778 1.1.1.1.12.1 martin ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
779 1.1.1.1.12.1 martin if (ret < 0)
780 1.1.1.1.12.1 martin return -FDT_ERR_BADOVERLAY;
781 1.1.1.1.12.1 martin
782 1.1.1.1.12.1 martin /* get the target of the fragment */
783 1.1.1.1.12.1 martin ret = overlay_get_target(fdt, fdto, fragment, &target_path);
784 1.1.1.1.12.1 martin if (ret < 0)
785 1.1.1.1.12.1 martin return ret;
786 1.1.1.1.12.1 martin target = ret;
787 1.1.1.1.12.1 martin
788 1.1.1.1.12.1 martin /* if we have a target path use */
789 1.1.1.1.12.1 martin if (!target_path) {
790 1.1.1.1.12.1 martin ret = get_path_len(fdt, target);
791 1.1.1.1.12.1 martin if (ret < 0)
792 1.1.1.1.12.1 martin return ret;
793 1.1.1.1.12.1 martin len = ret;
794 1.1.1.1.12.1 martin } else {
795 1.1.1.1.12.1 martin len = strlen(target_path);
796 1.1.1.1.12.1 martin }
797 1.1.1.1.12.1 martin
798 1.1.1.1.12.1 martin ret = fdt_setprop_placeholder(fdt, root_sym, name,
799 1.1.1.1.12.1 martin len + (len > 1) + rel_path_len + 1, &p);
800 1.1.1.1.12.1 martin if (ret < 0)
801 1.1.1.1.12.1 martin return ret;
802 1.1.1.1.12.1 martin
803 1.1.1.1.12.1 martin if (!target_path) {
804 1.1.1.1.12.1 martin /* again in case setprop_placeholder changed it */
805 1.1.1.1.12.1 martin ret = overlay_get_target(fdt, fdto, fragment, &target_path);
806 1.1.1.1.12.1 martin if (ret < 0)
807 1.1.1.1.12.1 martin return ret;
808 1.1.1.1.12.1 martin target = ret;
809 1.1.1.1.12.1 martin }
810 1.1.1.1.12.1 martin
811 1.1.1.1.12.1 martin buf = p;
812 1.1.1.1.12.1 martin if (len > 1) { /* target is not root */
813 1.1.1.1.12.1 martin if (!target_path) {
814 1.1.1.1.12.1 martin ret = fdt_get_path(fdt, target, buf, len + 1);
815 1.1.1.1.12.1 martin if (ret < 0)
816 1.1.1.1.12.1 martin return ret;
817 1.1.1.1.12.1 martin } else
818 1.1.1.1.12.1 martin memcpy(buf, target_path, len + 1);
819 1.1.1.1.12.1 martin
820 1.1.1.1.12.1 martin } else
821 1.1.1.1.12.1 martin len--;
822 1.1.1.1.12.1 martin
823 1.1.1.1.12.1 martin buf[len] = '/';
824 1.1.1.1.12.1 martin memcpy(buf + len + 1, rel_path, rel_path_len);
825 1.1.1.1.12.1 martin buf[len + 1 + rel_path_len] = '\0';
826 1.1.1.1.12.1 martin }
827 1.1.1.1.12.1 martin
828 1.1.1.1.12.1 martin return 0;
829 1.1.1.1.12.1 martin }
830 1.1.1.1.12.1 martin
831 1.1 skrll int fdt_overlay_apply(void *fdt, void *fdto)
832 1.1 skrll {
833 1.1.1.1.12.1 martin uint32_t delta;
834 1.1 skrll int ret;
835 1.1 skrll
836 1.1.1.1.12.1 martin FDT_RO_PROBE(fdt);
837 1.1.1.1.12.1 martin FDT_RO_PROBE(fdto);
838 1.1.1.1.12.1 martin
839 1.1.1.1.12.1 martin ret = fdt_find_max_phandle(fdt, &delta);
840 1.1.1.1.12.1 martin if (ret)
841 1.1.1.1.12.1 martin goto err;
842 1.1 skrll
843 1.1 skrll ret = overlay_adjust_local_phandles(fdto, delta);
844 1.1 skrll if (ret)
845 1.1 skrll goto err;
846 1.1 skrll
847 1.1 skrll ret = overlay_update_local_references(fdto, delta);
848 1.1 skrll if (ret)
849 1.1 skrll goto err;
850 1.1 skrll
851 1.1 skrll ret = overlay_fixup_phandles(fdt, fdto);
852 1.1 skrll if (ret)
853 1.1 skrll goto err;
854 1.1 skrll
855 1.1 skrll ret = overlay_merge(fdt, fdto);
856 1.1 skrll if (ret)
857 1.1 skrll goto err;
858 1.1 skrll
859 1.1.1.1.12.1 martin ret = overlay_symbol_update(fdt, fdto);
860 1.1.1.1.12.1 martin if (ret)
861 1.1.1.1.12.1 martin goto err;
862 1.1.1.1.12.1 martin
863 1.1 skrll /*
864 1.1 skrll * The overlay has been damaged, erase its magic.
865 1.1 skrll */
866 1.1 skrll fdt_set_magic(fdto, ~0);
867 1.1 skrll
868 1.1 skrll return 0;
869 1.1 skrll
870 1.1 skrll err:
871 1.1 skrll /*
872 1.1 skrll * The overlay might have been damaged, erase its magic.
873 1.1 skrll */
874 1.1 skrll fdt_set_magic(fdto, ~0);
875 1.1 skrll
876 1.1 skrll /*
877 1.1 skrll * The base device tree might have been damaged, erase its
878 1.1 skrll * magic.
879 1.1 skrll */
880 1.1 skrll fdt_set_magic(fdt, ~0);
881 1.1 skrll
882 1.1 skrll return ret;
883 1.1 skrll }
884