]>
Commit | Line | Data |
---|---|---|
e7108d0e MK |
1 | /*\r |
2 | * libfdt - Flat Device Tree manipulation\r | |
3 | * Copyright (C) 2016 Free Electrons\r | |
4 | * Copyright (C) 2016 NextThing Co.\r | |
5 | *\r | |
6 | * libfdt is dual licensed: you can use it either under the terms of\r | |
7 | * the GPL, or the BSD license, at your option.\r | |
8 | *\r | |
9 | * a) This library is free software; you can redistribute it and/or\r | |
10 | * modify it under the terms of the GNU General Public License as\r | |
11 | * published by the Free Software Foundation; either version 2 of the\r | |
12 | * License, or (at your option) any later version.\r | |
13 | *\r | |
14 | * This library is distributed in the hope that it will be useful,\r | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of\r | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r | |
17 | * GNU General Public License for more details.\r | |
18 | *\r | |
19 | * You should have received a copy of the GNU General Public\r | |
20 | * License along with this library; if not, write to the Free\r | |
21 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,\r | |
22 | * MA 02110-1301 USA\r | |
23 | *\r | |
24 | * Alternatively,\r | |
25 | *\r | |
26 | * b) Redistribution and use in source and binary forms, with or\r | |
27 | * without modification, are permitted provided that the following\r | |
28 | * conditions are met:\r | |
29 | *\r | |
30 | * 1. Redistributions of source code must retain the above\r | |
31 | * copyright notice, this list of conditions and the following\r | |
32 | * disclaimer.\r | |
33 | * 2. Redistributions in binary form must reproduce the above\r | |
34 | * copyright notice, this list of conditions and the following\r | |
35 | * disclaimer in the documentation and/or other materials\r | |
36 | * provided with the distribution.\r | |
37 | *\r | |
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r | |
39 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r | |
40 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r | |
41 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r | |
42 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r | |
43 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r | |
44 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r | |
45 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r | |
46 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r | |
47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r | |
48 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r | |
49 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r | |
50 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r | |
51 | */\r | |
52 | #include "libfdt_env.h"\r | |
53 | \r | |
54 | #include <fdt.h>\r | |
55 | #include <libfdt.h>\r | |
56 | \r | |
57 | #include "libfdt_internal.h"\r | |
58 | \r | |
59 | /**\r | |
60 | * overlay_get_target_phandle - retrieves the target phandle of a fragment\r | |
61 | * @fdto: pointer to the device tree overlay blob\r | |
62 | * @fragment: node offset of the fragment in the overlay\r | |
63 | *\r | |
64 | * overlay_get_target_phandle() retrieves the target phandle of an\r | |
65 | * overlay fragment when that fragment uses a phandle (target\r | |
66 | * property) instead of a path (target-path property).\r | |
67 | *\r | |
68 | * returns:\r | |
69 | * the phandle pointed by the target property\r | |
70 | * 0, if the phandle was not found\r | |
71 | * -1, if the phandle was malformed\r | |
72 | */\r | |
73 | static uint32_t\r | |
74 | overlay_get_target_phandle (\r | |
75 | const void *fdto,\r | |
76 | int fragment\r | |
77 | )\r | |
78 | {\r | |
79 | const fdt32_t *val;\r | |
80 | int len;\r | |
81 | \r | |
82 | val = fdt_getprop (fdto, fragment, "target", &len);\r | |
83 | if (!val) {\r | |
84 | return 0;\r | |
85 | }\r | |
86 | \r | |
87 | if ((len != sizeof (*val)) || (fdt32_to_cpu (*val) == (uint32_t)-1)) {\r | |
88 | return (uint32_t)-1;\r | |
89 | }\r | |
90 | \r | |
91 | return fdt32_to_cpu (*val);\r | |
92 | }\r | |
93 | \r | |
94 | /**\r | |
95 | * overlay_get_target - retrieves the offset of a fragment's target\r | |
96 | * @fdt: Base device tree blob\r | |
97 | * @fdto: Device tree overlay blob\r | |
98 | * @fragment: node offset of the fragment in the overlay\r | |
99 | * @pathp: pointer which receives the path of the target (or NULL)\r | |
100 | *\r | |
101 | * overlay_get_target() retrieves the target offset in the base\r | |
102 | * device tree of a fragment, no matter how the actual targetting is\r | |
103 | * done (through a phandle or a path)\r | |
104 | *\r | |
105 | * returns:\r | |
106 | * the targetted node offset in the base device tree\r | |
107 | * Negative error code on error\r | |
108 | */\r | |
109 | static int\r | |
110 | overlay_get_target (\r | |
111 | const void *fdt,\r | |
112 | const void *fdto,\r | |
113 | int fragment,\r | |
114 | char const **pathp\r | |
115 | )\r | |
116 | {\r | |
117 | uint32_t phandle;\r | |
118 | const char *path = NULL;\r | |
119 | int path_len = 0, ret;\r | |
120 | \r | |
121 | /* Try first to do a phandle based lookup */\r | |
122 | phandle = overlay_get_target_phandle (fdto, fragment);\r | |
123 | if (phandle == (uint32_t)-1) {\r | |
124 | return -FDT_ERR_BADPHANDLE;\r | |
125 | }\r | |
126 | \r | |
127 | /* no phandle, try path */\r | |
128 | if (!phandle) {\r | |
129 | /* And then a path based lookup */\r | |
130 | path = fdt_getprop (fdto, fragment, "target-path", &path_len);\r | |
131 | if (path) {\r | |
132 | ret = fdt_path_offset (fdt, path);\r | |
133 | } else {\r | |
134 | ret = path_len;\r | |
135 | }\r | |
136 | } else {\r | |
137 | ret = fdt_node_offset_by_phandle (fdt, phandle);\r | |
138 | }\r | |
139 | \r | |
140 | /*\r | |
141 | * If we haven't found either a target or a\r | |
142 | * target-path property in a node that contains a\r | |
143 | * __overlay__ subnode (we wouldn't be called\r | |
144 | * otherwise), consider it a improperly written\r | |
145 | * overlay\r | |
146 | */\r | |
147 | if ((ret < 0) && (path_len == -FDT_ERR_NOTFOUND)) {\r | |
148 | ret = -FDT_ERR_BADOVERLAY;\r | |
149 | }\r | |
150 | \r | |
151 | /* return on error */\r | |
152 | if (ret < 0) {\r | |
153 | return ret;\r | |
154 | }\r | |
155 | \r | |
156 | /* return pointer to path (if available) */\r | |
157 | if (pathp) {\r | |
158 | *pathp = path ? path : NULL;\r | |
159 | }\r | |
160 | \r | |
161 | return ret;\r | |
162 | }\r | |
163 | \r | |
164 | /**\r | |
165 | * overlay_phandle_add_offset - Increases a phandle by an offset\r | |
166 | * @fdt: Base device tree blob\r | |
167 | * @node: Device tree overlay blob\r | |
168 | * @name: Name of the property to modify (phandle or linux,phandle)\r | |
169 | * @delta: offset to apply\r | |
170 | *\r | |
171 | * overlay_phandle_add_offset() increments a node phandle by a given\r | |
172 | * offset.\r | |
173 | *\r | |
174 | * returns:\r | |
175 | * 0 on success.\r | |
176 | * Negative error code on error\r | |
177 | */\r | |
178 | static int\r | |
179 | overlay_phandle_add_offset (\r | |
180 | void *fdt,\r | |
181 | int node,\r | |
182 | const char *name,\r | |
183 | uint32_t delta\r | |
184 | )\r | |
185 | {\r | |
186 | const fdt32_t *val;\r | |
187 | uint32_t adj_val;\r | |
188 | int len;\r | |
189 | \r | |
190 | val = fdt_getprop (fdt, node, name, &len);\r | |
191 | if (!val) {\r | |
192 | return len;\r | |
193 | }\r | |
194 | \r | |
195 | if (len != sizeof (*val)) {\r | |
196 | return -FDT_ERR_BADPHANDLE;\r | |
197 | }\r | |
198 | \r | |
199 | adj_val = fdt32_to_cpu (*val);\r | |
200 | if ((adj_val + delta) < adj_val) {\r | |
201 | return -FDT_ERR_NOPHANDLES;\r | |
202 | }\r | |
203 | \r | |
204 | adj_val += delta;\r | |
205 | if (adj_val == (uint32_t)-1) {\r | |
206 | return -FDT_ERR_NOPHANDLES;\r | |
207 | }\r | |
208 | \r | |
209 | return fdt_setprop_inplace_u32 (fdt, node, name, adj_val);\r | |
210 | }\r | |
211 | \r | |
212 | /**\r | |
213 | * overlay_adjust_node_phandles - Offsets the phandles of a node\r | |
214 | * @fdto: Device tree overlay blob\r | |
215 | * @node: Offset of the node we want to adjust\r | |
216 | * @delta: Offset to shift the phandles of\r | |
217 | *\r | |
218 | * overlay_adjust_node_phandles() adds a constant to all the phandles\r | |
219 | * of a given node. This is mainly use as part of the overlay\r | |
220 | * application process, when we want to update all the overlay\r | |
221 | * phandles to not conflict with the overlays of the base device tree.\r | |
222 | *\r | |
223 | * returns:\r | |
224 | * 0 on success\r | |
225 | * Negative error code on failure\r | |
226 | */\r | |
227 | static int\r | |
228 | overlay_adjust_node_phandles (\r | |
229 | void *fdto,\r | |
230 | int node,\r | |
231 | uint32_t delta\r | |
232 | )\r | |
233 | {\r | |
234 | int child;\r | |
235 | int ret;\r | |
236 | \r | |
237 | ret = overlay_phandle_add_offset (fdto, node, "phandle", delta);\r | |
238 | if (ret && (ret != -FDT_ERR_NOTFOUND)) {\r | |
239 | return ret;\r | |
240 | }\r | |
241 | \r | |
242 | ret = overlay_phandle_add_offset (fdto, node, "linux,phandle", delta);\r | |
243 | if (ret && (ret != -FDT_ERR_NOTFOUND)) {\r | |
244 | return ret;\r | |
245 | }\r | |
246 | \r | |
247 | fdt_for_each_subnode (child, fdto, node) {\r | |
248 | ret = overlay_adjust_node_phandles (fdto, child, delta);\r | |
249 | if (ret) {\r | |
250 | return ret;\r | |
251 | }\r | |
252 | }\r | |
253 | \r | |
254 | return 0;\r | |
255 | }\r | |
256 | \r | |
257 | /**\r | |
258 | * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay\r | |
259 | * @fdto: Device tree overlay blob\r | |
260 | * @delta: Offset to shift the phandles of\r | |
261 | *\r | |
262 | * overlay_adjust_local_phandles() adds a constant to all the\r | |
263 | * phandles of an overlay. This is mainly use as part of the overlay\r | |
264 | * application process, when we want to update all the overlay\r | |
265 | * phandles to not conflict with the overlays of the base device tree.\r | |
266 | *\r | |
267 | * returns:\r | |
268 | * 0 on success\r | |
269 | * Negative error code on failure\r | |
270 | */\r | |
271 | static int\r | |
272 | overlay_adjust_local_phandles (\r | |
273 | void *fdto,\r | |
274 | uint32_t delta\r | |
275 | )\r | |
276 | {\r | |
277 | /*\r | |
278 | * Start adjusting the phandles from the overlay root\r | |
279 | */\r | |
280 | return overlay_adjust_node_phandles (fdto, 0, delta);\r | |
281 | }\r | |
282 | \r | |
283 | /**\r | |
284 | * overlay_update_local_node_references - Adjust the overlay references\r | |
285 | * @fdto: Device tree overlay blob\r | |
286 | * @tree_node: Node offset of the node to operate on\r | |
287 | * @fixup_node: Node offset of the matching local fixups node\r | |
288 | * @delta: Offset to shift the phandles of\r | |
289 | *\r | |
290 | * overlay_update_local_nodes_references() update the phandles\r | |
291 | * pointing to a node within the device tree overlay by adding a\r | |
292 | * constant delta.\r | |
293 | *\r | |
294 | * This is mainly used as part of a device tree application process,\r | |
295 | * where you want the device tree overlays phandles to not conflict\r | |
296 | * with the ones from the base device tree before merging them.\r | |
297 | *\r | |
298 | * returns:\r | |
299 | * 0 on success\r | |
300 | * Negative error code on failure\r | |
301 | */\r | |
302 | static int\r | |
303 | overlay_update_local_node_references (\r | |
304 | void *fdto,\r | |
305 | int tree_node,\r | |
306 | int fixup_node,\r | |
307 | uint32_t delta\r | |
308 | )\r | |
309 | {\r | |
310 | int fixup_prop;\r | |
311 | int fixup_child;\r | |
312 | int ret;\r | |
313 | \r | |
314 | fdt_for_each_property_offset (fixup_prop, fdto, fixup_node) {\r | |
315 | const fdt32_t *fixup_val;\r | |
316 | const char *tree_val;\r | |
317 | const char *name;\r | |
318 | int fixup_len;\r | |
319 | int tree_len;\r | |
320 | int i;\r | |
321 | \r | |
322 | fixup_val = fdt_getprop_by_offset (\r | |
323 | fdto,\r | |
324 | fixup_prop,\r | |
325 | &name,\r | |
326 | &fixup_len\r | |
327 | );\r | |
328 | if (!fixup_val) {\r | |
329 | return fixup_len;\r | |
330 | }\r | |
331 | \r | |
332 | if (fixup_len % sizeof (uint32_t)) {\r | |
333 | return -FDT_ERR_BADOVERLAY;\r | |
334 | }\r | |
335 | \r | |
336 | tree_val = fdt_getprop (fdto, tree_node, name, &tree_len);\r | |
337 | if (!tree_val) {\r | |
338 | if (tree_len == -FDT_ERR_NOTFOUND) {\r | |
339 | return -FDT_ERR_BADOVERLAY;\r | |
340 | }\r | |
341 | \r | |
342 | return tree_len;\r | |
343 | }\r | |
344 | \r | |
345 | for (i = 0; i < (fixup_len / sizeof (uint32_t)); i++) {\r | |
346 | fdt32_t adj_val;\r | |
347 | uint32_t poffset;\r | |
348 | \r | |
349 | poffset = fdt32_to_cpu (fixup_val[i]);\r | |
350 | \r | |
351 | /*\r | |
352 | * phandles to fixup can be unaligned.\r | |
353 | *\r | |
354 | * Use a memcpy for the architectures that do\r | |
355 | * not support unaligned accesses.\r | |
356 | */\r | |
357 | memcpy (&adj_val, tree_val + poffset, sizeof (adj_val));\r | |
358 | \r | |
359 | adj_val = cpu_to_fdt32 (fdt32_to_cpu (adj_val) + delta);\r | |
360 | \r | |
361 | ret = fdt_setprop_inplace_namelen_partial (\r | |
362 | fdto,\r | |
363 | tree_node,\r | |
364 | name,\r | |
365 | strlen (name),\r | |
366 | poffset,\r | |
367 | &adj_val,\r | |
368 | sizeof (adj_val)\r | |
369 | );\r | |
370 | if (ret == -FDT_ERR_NOSPACE) {\r | |
371 | return -FDT_ERR_BADOVERLAY;\r | |
372 | }\r | |
373 | \r | |
374 | if (ret) {\r | |
375 | return ret;\r | |
376 | }\r | |
377 | }\r | |
378 | }\r | |
379 | \r | |
380 | fdt_for_each_subnode (fixup_child, fdto, fixup_node) {\r | |
381 | const char *fixup_child_name = fdt_get_name (\r | |
382 | fdto,\r | |
383 | fixup_child,\r | |
384 | NULL\r | |
385 | );\r | |
386 | int tree_child;\r | |
387 | \r | |
388 | tree_child = fdt_subnode_offset (\r | |
389 | fdto,\r | |
390 | tree_node,\r | |
391 | fixup_child_name\r | |
392 | );\r | |
393 | if (tree_child == -FDT_ERR_NOTFOUND) {\r | |
394 | return -FDT_ERR_BADOVERLAY;\r | |
395 | }\r | |
396 | \r | |
397 | if (tree_child < 0) {\r | |
398 | return tree_child;\r | |
399 | }\r | |
400 | \r | |
401 | ret = overlay_update_local_node_references (\r | |
402 | fdto,\r | |
403 | tree_child,\r | |
404 | fixup_child,\r | |
405 | delta\r | |
406 | );\r | |
407 | if (ret) {\r | |
408 | return ret;\r | |
409 | }\r | |
410 | }\r | |
411 | \r | |
412 | return 0;\r | |
413 | }\r | |
414 | \r | |
415 | /**\r | |
416 | * overlay_update_local_references - Adjust the overlay references\r | |
417 | * @fdto: Device tree overlay blob\r | |
418 | * @delta: Offset to shift the phandles of\r | |
419 | *\r | |
420 | * overlay_update_local_references() update all the phandles pointing\r | |
421 | * to a node within the device tree overlay by adding a constant\r | |
422 | * delta to not conflict with the base overlay.\r | |
423 | *\r | |
424 | * This is mainly used as part of a device tree application process,\r | |
425 | * where you want the device tree overlays phandles to not conflict\r | |
426 | * with the ones from the base device tree before merging them.\r | |
427 | *\r | |
428 | * returns:\r | |
429 | * 0 on success\r | |
430 | * Negative error code on failure\r | |
431 | */\r | |
432 | static int\r | |
433 | overlay_update_local_references (\r | |
434 | void *fdto,\r | |
435 | uint32_t delta\r | |
436 | )\r | |
437 | {\r | |
438 | int fixups;\r | |
439 | \r | |
440 | fixups = fdt_path_offset (fdto, "/__local_fixups__");\r | |
441 | if (fixups < 0) {\r | |
442 | /* There's no local phandles to adjust, bail out */\r | |
443 | if (fixups == -FDT_ERR_NOTFOUND) {\r | |
444 | return 0;\r | |
445 | }\r | |
446 | \r | |
447 | return fixups;\r | |
448 | }\r | |
449 | \r | |
450 | /*\r | |
451 | * Update our local references from the root of the tree\r | |
452 | */\r | |
453 | return overlay_update_local_node_references (\r | |
454 | fdto,\r | |
455 | 0,\r | |
456 | fixups,\r | |
457 | delta\r | |
458 | );\r | |
459 | }\r | |
460 | \r | |
461 | /**\r | |
462 | * overlay_fixup_one_phandle - Set an overlay phandle to the base one\r | |
463 | * @fdt: Base Device Tree blob\r | |
464 | * @fdto: Device tree overlay blob\r | |
465 | * @symbols_off: Node offset of the symbols node in the base device tree\r | |
466 | * @path: Path to a node holding a phandle in the overlay\r | |
467 | * @path_len: number of path characters to consider\r | |
468 | * @name: Name of the property holding the phandle reference in the overlay\r | |
469 | * @name_len: number of name characters to consider\r | |
470 | * @poffset: Offset within the overlay property where the phandle is stored\r | |
471 | * @label: Label of the node referenced by the phandle\r | |
472 | *\r | |
473 | * overlay_fixup_one_phandle() resolves an overlay phandle pointing to\r | |
474 | * a node in the base device tree.\r | |
475 | *\r | |
476 | * This is part of the device tree overlay application process, when\r | |
477 | * you want all the phandles in the overlay to point to the actual\r | |
478 | * base dt nodes.\r | |
479 | *\r | |
480 | * returns:\r | |
481 | * 0 on success\r | |
482 | * Negative error code on failure\r | |
483 | */\r | |
484 | static int\r | |
485 | overlay_fixup_one_phandle (\r | |
486 | void *fdt,\r | |
487 | void *fdto,\r | |
488 | int symbols_off,\r | |
489 | const char *path,\r | |
490 | uint32_t path_len,\r | |
491 | const char *name,\r | |
492 | uint32_t name_len,\r | |
493 | int poffset,\r | |
494 | const char *label\r | |
495 | )\r | |
496 | {\r | |
497 | const char *symbol_path;\r | |
498 | uint32_t phandle;\r | |
499 | fdt32_t phandle_prop;\r | |
500 | int symbol_off, fixup_off;\r | |
501 | int prop_len;\r | |
502 | \r | |
503 | if (symbols_off < 0) {\r | |
504 | return symbols_off;\r | |
505 | }\r | |
506 | \r | |
507 | symbol_path = fdt_getprop (\r | |
508 | fdt,\r | |
509 | symbols_off,\r | |
510 | label,\r | |
511 | &prop_len\r | |
512 | );\r | |
513 | if (!symbol_path) {\r | |
514 | return prop_len;\r | |
515 | }\r | |
516 | \r | |
517 | symbol_off = fdt_path_offset (fdt, symbol_path);\r | |
518 | if (symbol_off < 0) {\r | |
519 | return symbol_off;\r | |
520 | }\r | |
521 | \r | |
522 | phandle = fdt_get_phandle (fdt, symbol_off);\r | |
523 | if (!phandle) {\r | |
524 | return -FDT_ERR_NOTFOUND;\r | |
525 | }\r | |
526 | \r | |
527 | fixup_off = fdt_path_offset_namelen (fdto, path, path_len);\r | |
528 | if (fixup_off == -FDT_ERR_NOTFOUND) {\r | |
529 | return -FDT_ERR_BADOVERLAY;\r | |
530 | }\r | |
531 | \r | |
532 | if (fixup_off < 0) {\r | |
533 | return fixup_off;\r | |
534 | }\r | |
535 | \r | |
536 | phandle_prop = cpu_to_fdt32 (phandle);\r | |
537 | return fdt_setprop_inplace_namelen_partial (\r | |
538 | fdto,\r | |
539 | fixup_off,\r | |
540 | name,\r | |
541 | name_len,\r | |
542 | poffset,\r | |
543 | &phandle_prop,\r | |
544 | sizeof (phandle_prop)\r | |
545 | );\r | |
546 | }\r | |
547 | \r | |
548 | unsigned long\r | |
549 | strtoul (\r | |
550 | const char *nptr,\r | |
551 | char **endptr,\r | |
552 | int base\r | |
553 | );\r | |
554 | \r | |
555 | /**\r | |
556 | * overlay_fixup_phandle - Set an overlay phandle to the base one\r | |
557 | * @fdt: Base Device Tree blob\r | |
558 | * @fdto: Device tree overlay blob\r | |
559 | * @symbols_off: Node offset of the symbols node in the base device tree\r | |
560 | * @property: Property offset in the overlay holding the list of fixups\r | |
561 | *\r | |
562 | * overlay_fixup_phandle() resolves all the overlay phandles pointed\r | |
563 | * to in a __fixups__ property, and updates them to match the phandles\r | |
564 | * in use in the base device tree.\r | |
565 | *\r | |
566 | * This is part of the device tree overlay application process, when\r | |
567 | * you want all the phandles in the overlay to point to the actual\r | |
568 | * base dt nodes.\r | |
569 | *\r | |
570 | * returns:\r | |
571 | * 0 on success\r | |
572 | * Negative error code on failure\r | |
573 | */\r | |
574 | static int\r | |
575 | overlay_fixup_phandle (\r | |
576 | void *fdt,\r | |
577 | void *fdto,\r | |
578 | int symbols_off,\r | |
579 | int property\r | |
580 | )\r | |
581 | {\r | |
582 | const char *value;\r | |
583 | const char *label;\r | |
584 | int len;\r | |
585 | \r | |
586 | value = fdt_getprop_by_offset (\r | |
587 | fdto,\r | |
588 | property,\r | |
589 | &label,\r | |
590 | &len\r | |
591 | );\r | |
592 | if (!value) {\r | |
593 | if (len == -FDT_ERR_NOTFOUND) {\r | |
594 | return -FDT_ERR_INTERNAL;\r | |
595 | }\r | |
596 | \r | |
597 | return len;\r | |
598 | }\r | |
599 | \r | |
600 | do {\r | |
601 | const char *path, *name, *fixup_end;\r | |
602 | const char *fixup_str = value;\r | |
603 | uint32_t path_len, name_len;\r | |
604 | uint32_t fixup_len;\r | |
605 | char *sep, *endptr;\r | |
606 | int poffset, ret;\r | |
607 | \r | |
608 | fixup_end = memchr (value, '\0', len);\r | |
609 | if (!fixup_end) {\r | |
610 | return -FDT_ERR_BADOVERLAY;\r | |
611 | }\r | |
612 | \r | |
613 | fixup_len = fixup_end - fixup_str;\r | |
614 | \r | |
615 | len -= fixup_len + 1;\r | |
616 | value += fixup_len + 1;\r | |
617 | \r | |
618 | path = fixup_str;\r | |
619 | sep = memchr (fixup_str, ':', fixup_len);\r | |
620 | if (!sep || (*sep != ':')) {\r | |
621 | return -FDT_ERR_BADOVERLAY;\r | |
622 | }\r | |
623 | \r | |
624 | path_len = sep - path;\r | |
625 | if (path_len == (fixup_len - 1)) {\r | |
626 | return -FDT_ERR_BADOVERLAY;\r | |
627 | }\r | |
628 | \r | |
629 | fixup_len -= path_len + 1;\r | |
630 | name = sep + 1;\r | |
631 | sep = memchr (name, ':', fixup_len);\r | |
632 | if (!sep || (*sep != ':')) {\r | |
633 | return -FDT_ERR_BADOVERLAY;\r | |
634 | }\r | |
635 | \r | |
636 | name_len = sep - name;\r | |
637 | if (!name_len) {\r | |
638 | return -FDT_ERR_BADOVERLAY;\r | |
639 | }\r | |
640 | \r | |
641 | poffset = strtoul (sep + 1, &endptr, 10);\r | |
642 | if ((*endptr != '\0') || (endptr <= (sep + 1))) {\r | |
643 | return -FDT_ERR_BADOVERLAY;\r | |
644 | }\r | |
645 | \r | |
646 | ret = overlay_fixup_one_phandle (\r | |
647 | fdt,\r | |
648 | fdto,\r | |
649 | symbols_off,\r | |
650 | path,\r | |
651 | path_len,\r | |
652 | name,\r | |
653 | name_len,\r | |
654 | poffset,\r | |
655 | label\r | |
656 | );\r | |
657 | if (ret) {\r | |
658 | return ret;\r | |
659 | }\r | |
660 | } while (len > 0);\r | |
661 | \r | |
662 | return 0;\r | |
663 | }\r | |
664 | \r | |
665 | /**\r | |
666 | * overlay_fixup_phandles - Resolve the overlay phandles to the base\r | |
667 | * device tree\r | |
668 | * @fdt: Base Device Tree blob\r | |
669 | * @fdto: Device tree overlay blob\r | |
670 | *\r | |
671 | * overlay_fixup_phandles() resolves all the overlay phandles pointing\r | |
672 | * to nodes in the base device tree.\r | |
673 | *\r | |
674 | * This is one of the steps of the device tree overlay application\r | |
675 | * process, when you want all the phandles in the overlay to point to\r | |
676 | * the actual base dt nodes.\r | |
677 | *\r | |
678 | * returns:\r | |
679 | * 0 on success\r | |
680 | * Negative error code on failure\r | |
681 | */\r | |
682 | static int\r | |
683 | overlay_fixup_phandles (\r | |
684 | void *fdt,\r | |
685 | void *fdto\r | |
686 | )\r | |
687 | {\r | |
688 | int fixups_off, symbols_off;\r | |
689 | int property;\r | |
690 | \r | |
691 | /* We can have overlays without any fixups */\r | |
692 | fixups_off = fdt_path_offset (fdto, "/__fixups__");\r | |
693 | if (fixups_off == -FDT_ERR_NOTFOUND) {\r | |
694 | return 0; /* nothing to do */\r | |
695 | }\r | |
696 | \r | |
697 | if (fixups_off < 0) {\r | |
698 | return fixups_off;\r | |
699 | }\r | |
700 | \r | |
701 | /* And base DTs without symbols */\r | |
702 | symbols_off = fdt_path_offset (fdt, "/__symbols__");\r | |
703 | if (((symbols_off < 0) && (symbols_off != -FDT_ERR_NOTFOUND))) {\r | |
704 | return symbols_off;\r | |
705 | }\r | |
706 | \r | |
707 | fdt_for_each_property_offset (property, fdto, fixups_off) {\r | |
708 | int ret;\r | |
709 | \r | |
710 | ret = overlay_fixup_phandle (fdt, fdto, symbols_off, property);\r | |
711 | if (ret) {\r | |
712 | return ret;\r | |
713 | }\r | |
714 | }\r | |
715 | \r | |
716 | return 0;\r | |
717 | }\r | |
718 | \r | |
719 | /**\r | |
720 | * overlay_apply_node - Merges a node into the base device tree\r | |
721 | * @fdt: Base Device Tree blob\r | |
722 | * @target: Node offset in the base device tree to apply the fragment to\r | |
723 | * @fdto: Device tree overlay blob\r | |
724 | * @node: Node offset in the overlay holding the changes to merge\r | |
725 | *\r | |
726 | * overlay_apply_node() merges a node into a target base device tree\r | |
727 | * node pointed.\r | |
728 | *\r | |
729 | * This is part of the final step in the device tree overlay\r | |
730 | * application process, when all the phandles have been adjusted and\r | |
731 | * resolved and you just have to merge overlay into the base device\r | |
732 | * tree.\r | |
733 | *\r | |
734 | * returns:\r | |
735 | * 0 on success\r | |
736 | * Negative error code on failure\r | |
737 | */\r | |
738 | static int\r | |
739 | overlay_apply_node (\r | |
740 | void *fdt,\r | |
741 | int target,\r | |
742 | void *fdto,\r | |
743 | int node\r | |
744 | )\r | |
745 | {\r | |
746 | int property;\r | |
747 | int subnode;\r | |
748 | \r | |
749 | fdt_for_each_property_offset (property, fdto, node) {\r | |
750 | const char *name;\r | |
751 | const void *prop;\r | |
752 | int prop_len;\r | |
753 | int ret;\r | |
754 | \r | |
755 | prop = fdt_getprop_by_offset (\r | |
756 | fdto,\r | |
757 | property,\r | |
758 | &name,\r | |
759 | &prop_len\r | |
760 | );\r | |
761 | if (prop_len == -FDT_ERR_NOTFOUND) {\r | |
762 | return -FDT_ERR_INTERNAL;\r | |
763 | }\r | |
764 | \r | |
765 | if (prop_len < 0) {\r | |
766 | return prop_len;\r | |
767 | }\r | |
768 | \r | |
769 | ret = fdt_setprop (fdt, target, name, prop, prop_len);\r | |
770 | if (ret) {\r | |
771 | return ret;\r | |
772 | }\r | |
773 | }\r | |
774 | \r | |
775 | fdt_for_each_subnode (subnode, fdto, node) {\r | |
776 | const char *name = fdt_get_name (fdto, subnode, NULL);\r | |
777 | int nnode;\r | |
778 | int ret;\r | |
779 | \r | |
780 | nnode = fdt_add_subnode (fdt, target, name);\r | |
781 | if (nnode == -FDT_ERR_EXISTS) {\r | |
782 | nnode = fdt_subnode_offset (fdt, target, name);\r | |
783 | if (nnode == -FDT_ERR_NOTFOUND) {\r | |
784 | return -FDT_ERR_INTERNAL;\r | |
785 | }\r | |
786 | }\r | |
787 | \r | |
788 | if (nnode < 0) {\r | |
789 | return nnode;\r | |
790 | }\r | |
791 | \r | |
792 | ret = overlay_apply_node (fdt, nnode, fdto, subnode);\r | |
793 | if (ret) {\r | |
794 | return ret;\r | |
795 | }\r | |
796 | }\r | |
797 | \r | |
798 | return 0;\r | |
799 | }\r | |
800 | \r | |
801 | /**\r | |
802 | * overlay_merge - Merge an overlay into its base device tree\r | |
803 | * @fdt: Base Device Tree blob\r | |
804 | * @fdto: Device tree overlay blob\r | |
805 | *\r | |
806 | * overlay_merge() merges an overlay into its base device tree.\r | |
807 | *\r | |
808 | * This is the next to last step in the device tree overlay application\r | |
809 | * process, when all the phandles have been adjusted and resolved and\r | |
810 | * you just have to merge overlay into the base device tree.\r | |
811 | *\r | |
812 | * returns:\r | |
813 | * 0 on success\r | |
814 | * Negative error code on failure\r | |
815 | */\r | |
816 | static int\r | |
817 | overlay_merge (\r | |
818 | void *fdt,\r | |
819 | void *fdto\r | |
820 | )\r | |
821 | {\r | |
822 | int fragment;\r | |
823 | \r | |
824 | fdt_for_each_subnode (fragment, fdto, 0) {\r | |
825 | int overlay;\r | |
826 | int target;\r | |
827 | int ret;\r | |
828 | \r | |
829 | /*\r | |
830 | * Each fragments will have an __overlay__ node. If\r | |
831 | * they don't, it's not supposed to be merged\r | |
832 | */\r | |
833 | overlay = fdt_subnode_offset (fdto, fragment, "__overlay__");\r | |
834 | if (overlay == -FDT_ERR_NOTFOUND) {\r | |
835 | continue;\r | |
836 | }\r | |
837 | \r | |
838 | if (overlay < 0) {\r | |
839 | return overlay;\r | |
840 | }\r | |
841 | \r | |
842 | target = overlay_get_target (fdt, fdto, fragment, NULL);\r | |
843 | if (target < 0) {\r | |
844 | return target;\r | |
845 | }\r | |
846 | \r | |
847 | ret = overlay_apply_node (fdt, target, fdto, overlay);\r | |
848 | if (ret) {\r | |
849 | return ret;\r | |
850 | }\r | |
851 | }\r | |
852 | \r | |
853 | return 0;\r | |
854 | }\r | |
855 | \r | |
856 | static int\r | |
857 | get_path_len (\r | |
858 | const void *fdt,\r | |
859 | int nodeoffset\r | |
860 | )\r | |
861 | {\r | |
862 | int len = 0, namelen;\r | |
863 | const char *name;\r | |
864 | \r | |
865 | FDT_CHECK_HEADER (fdt);\r | |
866 | \r | |
867 | for ( ; ;) {\r | |
868 | name = fdt_get_name (fdt, nodeoffset, &namelen);\r | |
869 | if (!name) {\r | |
870 | return namelen;\r | |
871 | }\r | |
872 | \r | |
873 | /* root? we're done */\r | |
874 | if (namelen == 0) {\r | |
875 | break;\r | |
876 | }\r | |
877 | \r | |
878 | nodeoffset = fdt_parent_offset (fdt, nodeoffset);\r | |
879 | if (nodeoffset < 0) {\r | |
880 | return nodeoffset;\r | |
881 | }\r | |
882 | \r | |
883 | len += namelen + 1;\r | |
884 | }\r | |
885 | \r | |
886 | /* in case of root pretend it's "/" */\r | |
887 | if (len == 0) {\r | |
888 | len++;\r | |
889 | }\r | |
890 | \r | |
891 | return len;\r | |
892 | }\r | |
893 | \r | |
894 | /**\r | |
895 | * overlay_symbol_update - Update the symbols of base tree after a merge\r | |
896 | * @fdt: Base Device Tree blob\r | |
897 | * @fdto: Device tree overlay blob\r | |
898 | *\r | |
899 | * overlay_symbol_update() updates the symbols of the base tree with the\r | |
900 | * symbols of the applied overlay\r | |
901 | *\r | |
902 | * This is the last step in the device tree overlay application\r | |
903 | * process, allowing the reference of overlay symbols by subsequent\r | |
904 | * overlay operations.\r | |
905 | *\r | |
906 | * returns:\r | |
907 | * 0 on success\r | |
908 | * Negative error code on failure\r | |
909 | */\r | |
910 | static int\r | |
911 | overlay_symbol_update (\r | |
912 | void *fdt,\r | |
913 | void *fdto\r | |
914 | )\r | |
915 | {\r | |
916 | int root_sym, ov_sym, prop, path_len, fragment, target;\r | |
917 | int len, frag_name_len, ret, rel_path_len;\r | |
918 | const char *s, *e;\r | |
919 | const char *path;\r | |
920 | const char *name;\r | |
921 | const char *frag_name;\r | |
922 | const char *rel_path;\r | |
923 | const char *target_path;\r | |
924 | char *buf;\r | |
925 | void *p;\r | |
926 | \r | |
927 | ov_sym = fdt_subnode_offset (fdto, 0, "__symbols__");\r | |
928 | \r | |
929 | /* if no overlay symbols exist no problem */\r | |
930 | if (ov_sym < 0) {\r | |
931 | return 0;\r | |
932 | }\r | |
933 | \r | |
934 | root_sym = fdt_subnode_offset (fdt, 0, "__symbols__");\r | |
935 | \r | |
936 | /* it no root symbols exist we should create them */\r | |
937 | if (root_sym == -FDT_ERR_NOTFOUND) {\r | |
938 | root_sym = fdt_add_subnode (fdt, 0, "__symbols__");\r | |
939 | }\r | |
940 | \r | |
941 | /* any error is fatal now */\r | |
942 | if (root_sym < 0) {\r | |
943 | return root_sym;\r | |
944 | }\r | |
945 | \r | |
946 | /* iterate over each overlay symbol */\r | |
947 | fdt_for_each_property_offset (prop, fdto, ov_sym) {\r | |
948 | path = fdt_getprop_by_offset (fdto, prop, &name, &path_len);\r | |
949 | if (!path) {\r | |
950 | return path_len;\r | |
951 | }\r | |
952 | \r | |
953 | /* verify it's a string property (terminated by a single \0) */\r | |
954 | if ((path_len < 1) || (memchr (path, '\0', path_len) != &path[path_len - 1])) {\r | |
955 | return -FDT_ERR_BADVALUE;\r | |
956 | }\r | |
957 | \r | |
958 | /* keep end marker to avoid strlen() */\r | |
959 | e = path + path_len;\r | |
960 | \r | |
961 | /* format: /<fragment-name>/__overlay__/<relative-subnode-path> */\r | |
962 | \r | |
963 | if (*path != '/') {\r | |
964 | return -FDT_ERR_BADVALUE;\r | |
965 | }\r | |
966 | \r | |
967 | /* get fragment name first */\r | |
968 | s = strchr (path + 1, '/');\r | |
969 | if (!s) {\r | |
970 | return -FDT_ERR_BADOVERLAY;\r | |
971 | }\r | |
972 | \r | |
973 | frag_name = path + 1;\r | |
974 | frag_name_len = s - path - 1;\r | |
975 | \r | |
976 | /* verify format; safe since "s" lies in \0 terminated prop */\r | |
977 | len = sizeof ("/__overlay__/") - 1;\r | |
978 | if (((e - s) < len) || memcmp (s, "/__overlay__/", len)) {\r | |
979 | return -FDT_ERR_BADOVERLAY;\r | |
980 | }\r | |
981 | \r | |
982 | rel_path = s + len;\r | |
983 | rel_path_len = e - rel_path;\r | |
984 | \r | |
985 | /* find the fragment index in which the symbol lies */\r | |
986 | ret = fdt_subnode_offset_namelen (\r | |
987 | fdto,\r | |
988 | 0,\r | |
989 | frag_name,\r | |
990 | frag_name_len\r | |
991 | );\r | |
992 | /* not found? */\r | |
993 | if (ret < 0) {\r | |
994 | return -FDT_ERR_BADOVERLAY;\r | |
995 | }\r | |
996 | \r | |
997 | fragment = ret;\r | |
998 | \r | |
999 | /* an __overlay__ subnode must exist */\r | |
1000 | ret = fdt_subnode_offset (fdto, fragment, "__overlay__");\r | |
1001 | if (ret < 0) {\r | |
1002 | return -FDT_ERR_BADOVERLAY;\r | |
1003 | }\r | |
1004 | \r | |
1005 | /* get the target of the fragment */\r | |
1006 | ret = overlay_get_target (fdt, fdto, fragment, &target_path);\r | |
1007 | if (ret < 0) {\r | |
1008 | return ret;\r | |
1009 | }\r | |
1010 | \r | |
1011 | target = ret;\r | |
1012 | \r | |
1013 | /* if we have a target path use */\r | |
1014 | if (!target_path) {\r | |
1015 | ret = get_path_len (fdt, target);\r | |
1016 | if (ret < 0) {\r | |
1017 | return ret;\r | |
1018 | }\r | |
1019 | \r | |
1020 | len = ret;\r | |
1021 | } else {\r | |
1022 | len = strlen (target_path);\r | |
1023 | }\r | |
1024 | \r | |
1025 | ret = fdt_setprop_placeholder (\r | |
1026 | fdt,\r | |
1027 | root_sym,\r | |
1028 | name,\r | |
1029 | len + (len > 1) + rel_path_len + 1,\r | |
1030 | &p\r | |
1031 | );\r | |
1032 | if (ret < 0) {\r | |
1033 | return ret;\r | |
1034 | }\r | |
1035 | \r | |
1036 | if (!target_path) {\r | |
1037 | /* again in case setprop_placeholder changed it */\r | |
1038 | ret = overlay_get_target (fdt, fdto, fragment, &target_path);\r | |
1039 | if (ret < 0) {\r | |
1040 | return ret;\r | |
1041 | }\r | |
1042 | \r | |
1043 | target = ret;\r | |
1044 | }\r | |
1045 | \r | |
1046 | buf = p;\r | |
1047 | if (len > 1) {\r | |
1048 | /* target is not root */\r | |
1049 | if (!target_path) {\r | |
1050 | ret = fdt_get_path (fdt, target, buf, len + 1);\r | |
1051 | if (ret < 0) {\r | |
1052 | return ret;\r | |
1053 | }\r | |
1054 | } else {\r | |
1055 | memcpy (buf, target_path, len + 1);\r | |
1056 | }\r | |
1057 | } else {\r | |
1058 | len--;\r | |
1059 | }\r | |
1060 | \r | |
1061 | buf[len] = '/';\r | |
1062 | memcpy (buf + len + 1, rel_path, rel_path_len);\r | |
1063 | buf[len + 1 + rel_path_len] = '\0';\r | |
1064 | }\r | |
1065 | \r | |
1066 | return 0;\r | |
1067 | }\r | |
1068 | \r | |
1069 | int\r | |
1070 | fdt_overlay_apply (\r | |
1071 | void *fdt,\r | |
1072 | void *fdto\r | |
1073 | )\r | |
1074 | {\r | |
1075 | uint32_t delta = fdt_get_max_phandle (fdt);\r | |
1076 | int ret;\r | |
1077 | \r | |
1078 | FDT_CHECK_HEADER (fdt);\r | |
1079 | FDT_CHECK_HEADER (fdto);\r | |
1080 | \r | |
1081 | ret = overlay_adjust_local_phandles (fdto, delta);\r | |
1082 | if (ret) {\r | |
1083 | goto err;\r | |
1084 | }\r | |
1085 | \r | |
1086 | ret = overlay_update_local_references (fdto, delta);\r | |
1087 | if (ret) {\r | |
1088 | goto err;\r | |
1089 | }\r | |
1090 | \r | |
1091 | ret = overlay_fixup_phandles (fdt, fdto);\r | |
1092 | if (ret) {\r | |
1093 | goto err;\r | |
1094 | }\r | |
1095 | \r | |
1096 | ret = overlay_merge (fdt, fdto);\r | |
1097 | if (ret) {\r | |
1098 | goto err;\r | |
1099 | }\r | |
1100 | \r | |
1101 | ret = overlay_symbol_update (fdt, fdto);\r | |
1102 | if (ret) {\r | |
1103 | goto err;\r | |
1104 | }\r | |
1105 | \r | |
1106 | /*\r | |
1107 | * The overlay has been damaged, erase its magic.\r | |
1108 | */\r | |
1109 | fdt_set_magic (fdto, ~0);\r | |
1110 | \r | |
1111 | return 0;\r | |
1112 | \r | |
1113 | err:\r | |
1114 | \r | |
1115 | /*\r | |
1116 | * The overlay might have been damaged, erase its magic.\r | |
1117 | */\r | |
1118 | fdt_set_magic (fdto, ~0);\r | |
1119 | \r | |
1120 | /*\r | |
1121 | * The base device tree might have been damaged, erase its\r | |
1122 | * magic.\r | |
1123 | */\r | |
1124 | fdt_set_magic (fdt, ~0);\r | |
1125 | \r | |
1126 | return ret;\r | |
1127 | }\r |