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