1
#include "libfdt_env.h"
6
#include "libfdt_internal.h"
9
* overlay_get_target_phandle - retrieves the target phandle of a fragment
10
* @fdto: pointer to the device tree overlay blob
11
* @fragment: node offset of the fragment in the overlay
13
* overlay_get_target_phandle() retrieves the target phandle of an
14
* overlay fragment when that fragment uses a phandle (target
15
* property) instead of a path (target-path property).
18
* the phandle pointed by the target property
19
* 0, if the phandle was not found
20
* -1, if the phandle was malformed
22
static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
27
val = fdt_getprop(fdto, fragment, "target", &len);
31
if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
34
return fdt32_to_cpu(*val);
38
* overlay_get_target - retrieves the offset of a fragment's target
39
* @fdt: Base device tree blob
40
* @fdto: Device tree overlay blob
41
* @fragment: node offset of the fragment in the overlay
43
* overlay_get_target() retrieves the target offset in the base
44
* device tree of a fragment, no matter how the actual targetting is
45
* done (through a phandle or a path)
48
* the targetted node offset in the base device tree
49
* Negative error code on error
51
static int overlay_get_target(const void *fdt, const void *fdto,
58
/* Try first to do a phandle based lookup */
59
phandle = overlay_get_target_phandle(fdto, fragment);
60
if (phandle == (uint32_t)-1)
61
return -FDT_ERR_BADPHANDLE;
64
return fdt_node_offset_by_phandle(fdt, phandle);
66
/* And then a path based lookup */
67
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
70
* If we haven't found either a target or a
71
* target-path property in a node that contains a
72
* __overlay__ subnode (we wouldn't be called
73
* otherwise), consider it a improperly written
76
if (path_len == -FDT_ERR_NOTFOUND)
77
return -FDT_ERR_BADOVERLAY;
82
return fdt_path_offset(fdt, path);
86
* overlay_phandle_add_offset - Increases a phandle by an offset
87
* @fdt: Base device tree blob
88
* @node: Device tree overlay blob
89
* @name: Name of the property to modify (phandle or linux,phandle)
90
* @delta: offset to apply
92
* overlay_phandle_add_offset() increments a node phandle by a given
97
* Negative error code on error
99
static int overlay_phandle_add_offset(void *fdt, int node,
100
const char *name, uint32_t delta)
106
val = fdt_getprop(fdt, node, name, &len);
110
if (len != sizeof(*val))
111
return -FDT_ERR_BADPHANDLE;
113
adj_val = fdt32_to_cpu(*val);
114
if ((adj_val + delta) < adj_val)
115
return -FDT_ERR_NOPHANDLES;
118
if (adj_val == (uint32_t)-1)
119
return -FDT_ERR_NOPHANDLES;
121
return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
125
* overlay_adjust_node_phandles - Offsets the phandles of a node
126
* @fdto: Device tree overlay blob
127
* @node: Offset of the node we want to adjust
128
* @delta: Offset to shift the phandles of
130
* overlay_adjust_node_phandles() adds a constant to all the phandles
131
* of a given node. This is mainly use as part of the overlay
132
* application process, when we want to update all the overlay
133
* phandles to not conflict with the overlays of the base device tree.
137
* Negative error code on failure
139
static int overlay_adjust_node_phandles(void *fdto, int node,
145
ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
146
if (ret && ret != -FDT_ERR_NOTFOUND)
149
ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
150
if (ret && ret != -FDT_ERR_NOTFOUND)
153
fdt_for_each_subnode(child, fdto, node) {
154
ret = overlay_adjust_node_phandles(fdto, child, delta);
163
* overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
164
* @fdto: Device tree overlay blob
165
* @delta: Offset to shift the phandles of
167
* overlay_adjust_local_phandles() adds a constant to all the
168
* phandles of an overlay. This is mainly use as part of the overlay
169
* application process, when we want to update all the overlay
170
* phandles to not conflict with the overlays of the base device tree.
174
* Negative error code on failure
176
static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
179
* Start adjusting the phandles from the overlay root
181
return overlay_adjust_node_phandles(fdto, 0, delta);
185
* overlay_update_local_node_references - Adjust the overlay references
186
* @fdto: Device tree overlay blob
187
* @tree_node: Node offset of the node to operate on
188
* @fixup_node: Node offset of the matching local fixups node
189
* @delta: Offset to shift the phandles of
191
* overlay_update_local_nodes_references() update the phandles
192
* pointing to a node within the device tree overlay by adding a
195
* This is mainly used as part of a device tree application process,
196
* where you want the device tree overlays phandles to not conflict
197
* with the ones from the base device tree before merging them.
201
* Negative error code on failure
203
static int overlay_update_local_node_references(void *fdto,
212
fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
213
const fdt32_t *fixup_val;
214
const char *tree_val;
220
fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
225
if (fixup_len % sizeof(uint32_t))
226
return -FDT_ERR_BADOVERLAY;
228
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
230
if (tree_len == -FDT_ERR_NOTFOUND)
231
return -FDT_ERR_BADOVERLAY;
236
for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
240
poffset = fdt32_to_cpu(fixup_val[i]);
243
* phandles to fixup can be unaligned.
245
* Use a memcpy for the architectures that do
246
* not support unaligned accesses.
248
memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
250
adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
252
ret = fdt_setprop_inplace_namelen_partial(fdto,
259
if (ret == -FDT_ERR_NOSPACE)
260
return -FDT_ERR_BADOVERLAY;
267
fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
268
const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
272
tree_child = fdt_subnode_offset(fdto, tree_node,
274
if (tree_child == -FDT_ERR_NOTFOUND)
275
return -FDT_ERR_BADOVERLAY;
279
ret = overlay_update_local_node_references(fdto,
291
* overlay_update_local_references - Adjust the overlay references
292
* @fdto: Device tree overlay blob
293
* @delta: Offset to shift the phandles of
295
* overlay_update_local_references() update all the phandles pointing
296
* to a node within the device tree overlay by adding a constant
297
* delta to not conflict with the base overlay.
299
* This is mainly used as part of a device tree application process,
300
* where you want the device tree overlays phandles to not conflict
301
* with the ones from the base device tree before merging them.
305
* Negative error code on failure
307
static int overlay_update_local_references(void *fdto, uint32_t delta)
311
fixups = fdt_path_offset(fdto, "/__local_fixups__");
313
/* There's no local phandles to adjust, bail out */
314
if (fixups == -FDT_ERR_NOTFOUND)
321
* Update our local references from the root of the tree
323
return overlay_update_local_node_references(fdto, 0, fixups,
328
* overlay_fixup_one_phandle - Set an overlay phandle to the base one
329
* @fdt: Base Device Tree blob
330
* @fdto: Device tree overlay blob
331
* @symbols_off: Node offset of the symbols node in the base device tree
332
* @path: Path to a node holding a phandle in the overlay
333
* @path_len: number of path characters to consider
334
* @name: Name of the property holding the phandle reference in the overlay
335
* @name_len: number of name characters to consider
336
* @poffset: Offset within the overlay property where the phandle is stored
337
* @label: Label of the node referenced by the phandle
339
* overlay_fixup_one_phandle() resolves an overlay phandle pointing to
340
* a node in the base device tree.
342
* This is part of the device tree overlay application process, when
343
* you want all the phandles in the overlay to point to the actual
348
* Negative error code on failure
350
static int overlay_fixup_one_phandle(void *fdt, void *fdto,
352
const char *path, uint32_t path_len,
353
const char *name, uint32_t name_len,
354
int poffset, const char *label)
356
const char *symbol_path;
358
fdt32_t phandle_prop;
359
int symbol_off, fixup_off;
365
symbol_path = fdt_getprop(fdt, symbols_off, label,
370
symbol_off = fdt_path_offset(fdt, symbol_path);
374
phandle = fdt_get_phandle(fdt, symbol_off);
376
return -FDT_ERR_NOTFOUND;
378
fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
379
if (fixup_off == -FDT_ERR_NOTFOUND)
380
return -FDT_ERR_BADOVERLAY;
384
phandle_prop = cpu_to_fdt32(phandle);
385
return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
386
name, name_len, poffset,
388
sizeof(phandle_prop));
392
* overlay_fixup_phandle - Set an overlay phandle to the base one
393
* @fdt: Base Device Tree blob
394
* @fdto: Device tree overlay blob
395
* @symbols_off: Node offset of the symbols node in the base device tree
396
* @property: Property offset in the overlay holding the list of fixups
398
* overlay_fixup_phandle() resolves all the overlay phandles pointed
399
* to in a __fixups__ property, and updates them to match the phandles
400
* in use in the base device tree.
402
* This is part of the device tree overlay application process, when
403
* you want all the phandles in the overlay to point to the actual
408
* Negative error code on failure
410
static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
417
value = fdt_getprop_by_offset(fdto, property,
420
if (len == -FDT_ERR_NOTFOUND)
421
return -FDT_ERR_INTERNAL;
427
const char *path, *name, *fixup_end;
428
const char *fixup_str = value;
429
uint32_t path_len, name_len;
434
fixup_end = memchr(value, '\0', len);
436
return -FDT_ERR_BADOVERLAY;
437
fixup_len = fixup_end - fixup_str;
439
len -= fixup_len + 1;
440
value += fixup_len + 1;
443
sep = memchr(fixup_str, ':', fixup_len);
444
if (!sep || *sep != ':')
445
return -FDT_ERR_BADOVERLAY;
447
path_len = sep - path;
448
if (path_len == (fixup_len - 1))
449
return -FDT_ERR_BADOVERLAY;
451
fixup_len -= path_len + 1;
453
sep = memchr(name, ':', fixup_len);
454
if (!sep || *sep != ':')
455
return -FDT_ERR_BADOVERLAY;
457
name_len = sep - name;
459
return -FDT_ERR_BADOVERLAY;
461
poffset = strtoul(sep + 1, &endptr, 10);
462
if ((*endptr != '\0') || (endptr <= (sep + 1)))
463
return -FDT_ERR_BADOVERLAY;
465
ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
466
path, path_len, name, name_len,
476
* overlay_fixup_phandles - Resolve the overlay phandles to the base
478
* @fdt: Base Device Tree blob
479
* @fdto: Device tree overlay blob
481
* overlay_fixup_phandles() resolves all the overlay phandles pointing
482
* to nodes in the base device tree.
484
* This is one of the steps of the device tree overlay application
485
* process, when you want all the phandles in the overlay to point to
486
* the actual base dt nodes.
490
* Negative error code on failure
492
static int overlay_fixup_phandles(void *fdt, void *fdto)
494
int fixups_off, symbols_off;
497
/* We can have overlays without any fixups */
498
fixups_off = fdt_path_offset(fdto, "/__fixups__");
499
if (fixups_off == -FDT_ERR_NOTFOUND)
500
return 0; /* nothing to do */
504
/* And base DTs without symbols */
505
symbols_off = fdt_path_offset(fdt, "/__symbols__");
506
if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
509
fdt_for_each_property_offset(property, fdto, fixups_off) {
512
ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
521
* overlay_apply_node - Merges a node into the base device tree
522
* @fdt: Base Device Tree blob
523
* @target: Node offset in the base device tree to apply the fragment to
524
* @fdto: Device tree overlay blob
525
* @node: Node offset in the overlay holding the changes to merge
527
* overlay_apply_node() merges a node into a target base device tree
530
* This is part of the final step in the device tree overlay
531
* application process, when all the phandles have been adjusted and
532
* resolved and you just have to merge overlay into the base device
537
* Negative error code on failure
539
static int overlay_apply_node(void *fdt, int target,
540
void *fdto, int node)
545
fdt_for_each_property_offset(property, fdto, node) {
551
prop = fdt_getprop_by_offset(fdto, property, &name,
553
if (prop_len == -FDT_ERR_NOTFOUND)
554
return -FDT_ERR_INTERNAL;
558
ret = fdt_setprop(fdt, target, name, prop, prop_len);
563
fdt_for_each_subnode(subnode, fdto, node) {
564
const char *name = fdt_get_name(fdto, subnode, NULL);
568
nnode = fdt_add_subnode(fdt, target, name);
569
if (nnode == -FDT_ERR_EXISTS) {
570
nnode = fdt_subnode_offset(fdt, target, name);
571
if (nnode == -FDT_ERR_NOTFOUND)
572
return -FDT_ERR_INTERNAL;
578
ret = overlay_apply_node(fdt, nnode, fdto, subnode);
587
* overlay_merge - Merge an overlay into its base device tree
588
* @fdt: Base Device Tree blob
589
* @fdto: Device tree overlay blob
591
* overlay_merge() merges an overlay into its base device tree.
593
* This is the final step in the device tree overlay application
594
* process, when all the phandles have been adjusted and resolved and
595
* you just have to merge overlay into the base device tree.
599
* Negative error code on failure
601
static int overlay_merge(void *fdt, void *fdto)
605
fdt_for_each_subnode(fragment, fdto, 0) {
611
* Each fragments will have an __overlay__ node. If
612
* they don't, it's not supposed to be merged
614
overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
615
if (overlay == -FDT_ERR_NOTFOUND)
621
target = overlay_get_target(fdt, fdto, fragment);
625
ret = overlay_apply_node(fdt, target, fdto, overlay);
633
int fdt_overlay_apply(void *fdt, void *fdto)
635
uint32_t delta = fdt_get_max_phandle(fdt);
638
FDT_CHECK_HEADER(fdt);
639
FDT_CHECK_HEADER(fdto);
641
ret = overlay_adjust_local_phandles(fdto, delta);
645
ret = overlay_update_local_references(fdto, delta);
649
ret = overlay_fixup_phandles(fdt, fdto);
653
ret = overlay_merge(fdt, fdto);
658
* The overlay has been damaged, erase its magic.
660
fdt_set_magic(fdto, ~0);
666
* The overlay might have been damaged, erase its magic.
668
fdt_set_magic(fdto, ~0);
671
* The base device tree might have been damaged, erase its
674
fdt_set_magic(fdt, ~0);