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