1*17f326ebSJerome Forissier // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
2b908c675SJens Wiklander /*
3b908c675SJens Wiklander * libfdt - Flat Device Tree manipulation
4b908c675SJens Wiklander * Copyright (C) 2006 David Gibson, IBM Corporation.
5b908c675SJens Wiklander */
6b908c675SJens Wiklander #include "libfdt_env.h"
7b908c675SJens Wiklander
8b908c675SJens Wiklander #include <fdt.h>
9b908c675SJens Wiklander #include <libfdt.h>
10b908c675SJens Wiklander
11b908c675SJens Wiklander #include "libfdt_internal.h"
12b908c675SJens Wiklander
fdt_blocks_misordered_(const void * fdt,int mem_rsv_size,int struct_size)1301d6a9daSBryan O'Donoghue static int fdt_blocks_misordered_(const void *fdt,
14b908c675SJens Wiklander int mem_rsv_size, int struct_size)
15b908c675SJens Wiklander {
16b908c675SJens Wiklander return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
17b908c675SJens Wiklander || (fdt_off_dt_struct(fdt) <
18b908c675SJens Wiklander (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
19b908c675SJens Wiklander || (fdt_off_dt_strings(fdt) <
20b908c675SJens Wiklander (fdt_off_dt_struct(fdt) + struct_size))
21b908c675SJens Wiklander || (fdt_totalsize(fdt) <
22b908c675SJens Wiklander (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
23b908c675SJens Wiklander }
24b908c675SJens Wiklander
fdt_rw_probe_(void * fdt)25*17f326ebSJerome Forissier static int fdt_rw_probe_(void *fdt)
26b908c675SJens Wiklander {
27*17f326ebSJerome Forissier FDT_RO_PROBE(fdt);
28b908c675SJens Wiklander
29b908c675SJens Wiklander if (fdt_version(fdt) < 17)
30b908c675SJens Wiklander return -FDT_ERR_BADVERSION;
3101d6a9daSBryan O'Donoghue if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
32b908c675SJens Wiklander fdt_size_dt_struct(fdt)))
33b908c675SJens Wiklander return -FDT_ERR_BADLAYOUT;
34b908c675SJens Wiklander if (fdt_version(fdt) > 17)
35b908c675SJens Wiklander fdt_set_version(fdt, 17);
36b908c675SJens Wiklander
37b908c675SJens Wiklander return 0;
38b908c675SJens Wiklander }
39b908c675SJens Wiklander
40*17f326ebSJerome Forissier #define FDT_RW_PROBE(fdt) \
41b908c675SJens Wiklander { \
4201d6a9daSBryan O'Donoghue int err_; \
43*17f326ebSJerome Forissier if ((err_ = fdt_rw_probe_(fdt)) != 0) \
4401d6a9daSBryan O'Donoghue return err_; \
45b908c675SJens Wiklander }
46b908c675SJens Wiklander
fdt_data_size_(void * fdt)4701d6a9daSBryan O'Donoghue static inline int fdt_data_size_(void *fdt)
48b908c675SJens Wiklander {
49b908c675SJens Wiklander return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
50b908c675SJens Wiklander }
51b908c675SJens Wiklander
fdt_splice_(void * fdt,void * splicepoint,int oldlen,int newlen)5201d6a9daSBryan O'Donoghue static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
53b908c675SJens Wiklander {
54b908c675SJens Wiklander char *p = splicepoint;
5501d6a9daSBryan O'Donoghue char *end = (char *)fdt + fdt_data_size_(fdt);
56b908c675SJens Wiklander
57b908c675SJens Wiklander if (((p + oldlen) < p) || ((p + oldlen) > end))
58b908c675SJens Wiklander return -FDT_ERR_BADOFFSET;
5901d6a9daSBryan O'Donoghue if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
6001d6a9daSBryan O'Donoghue return -FDT_ERR_BADOFFSET;
61b908c675SJens Wiklander if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
62b908c675SJens Wiklander return -FDT_ERR_NOSPACE;
63b908c675SJens Wiklander memmove(p + newlen, p + oldlen, end - p - oldlen);
64b908c675SJens Wiklander return 0;
65b908c675SJens Wiklander }
66b908c675SJens Wiklander
fdt_splice_mem_rsv_(void * fdt,struct fdt_reserve_entry * p,int oldn,int newn)6701d6a9daSBryan O'Donoghue static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
68b908c675SJens Wiklander int oldn, int newn)
69b908c675SJens Wiklander {
70b908c675SJens Wiklander int delta = (newn - oldn) * sizeof(*p);
71b908c675SJens Wiklander int err;
7201d6a9daSBryan O'Donoghue err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
73b908c675SJens Wiklander if (err)
74b908c675SJens Wiklander return err;
75b908c675SJens Wiklander fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
76b908c675SJens Wiklander fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
77b908c675SJens Wiklander return 0;
78b908c675SJens Wiklander }
79b908c675SJens Wiklander
fdt_splice_struct_(void * fdt,void * p,int oldlen,int newlen)8001d6a9daSBryan O'Donoghue static int fdt_splice_struct_(void *fdt, void *p,
81b908c675SJens Wiklander int oldlen, int newlen)
82b908c675SJens Wiklander {
83b908c675SJens Wiklander int delta = newlen - oldlen;
84b908c675SJens Wiklander int err;
85b908c675SJens Wiklander
8601d6a9daSBryan O'Donoghue if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
87b908c675SJens Wiklander return err;
88b908c675SJens Wiklander
89b908c675SJens Wiklander fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
90b908c675SJens Wiklander fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
91b908c675SJens Wiklander return 0;
92b908c675SJens Wiklander }
93b908c675SJens Wiklander
94*17f326ebSJerome Forissier /* Must only be used to roll back in case of error */
fdt_del_last_string_(void * fdt,const char * s)95*17f326ebSJerome Forissier static void fdt_del_last_string_(void *fdt, const char *s)
96*17f326ebSJerome Forissier {
97*17f326ebSJerome Forissier int newlen = strlen(s) + 1;
98*17f326ebSJerome Forissier
99*17f326ebSJerome Forissier fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
100*17f326ebSJerome Forissier }
101*17f326ebSJerome Forissier
fdt_splice_string_(void * fdt,int newlen)10201d6a9daSBryan O'Donoghue static int fdt_splice_string_(void *fdt, int newlen)
103b908c675SJens Wiklander {
104b908c675SJens Wiklander void *p = (char *)fdt
105b908c675SJens Wiklander + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
106b908c675SJens Wiklander int err;
107b908c675SJens Wiklander
10801d6a9daSBryan O'Donoghue if ((err = fdt_splice_(fdt, p, 0, newlen)))
109b908c675SJens Wiklander return err;
110b908c675SJens Wiklander
111b908c675SJens Wiklander fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
112b908c675SJens Wiklander return 0;
113b908c675SJens Wiklander }
114b908c675SJens Wiklander
fdt_find_add_string_(void * fdt,const char * s,int * allocated)115*17f326ebSJerome Forissier static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
116b908c675SJens Wiklander {
117b908c675SJens Wiklander char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
118b908c675SJens Wiklander const char *p;
119b908c675SJens Wiklander char *new;
120b908c675SJens Wiklander int len = strlen(s) + 1;
121b908c675SJens Wiklander int err;
122b908c675SJens Wiklander
123*17f326ebSJerome Forissier *allocated = 0;
124*17f326ebSJerome Forissier
12501d6a9daSBryan O'Donoghue p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
126b908c675SJens Wiklander if (p)
127b908c675SJens Wiklander /* found it */
128b908c675SJens Wiklander return (p - strtab);
129b908c675SJens Wiklander
130b908c675SJens Wiklander new = strtab + fdt_size_dt_strings(fdt);
13101d6a9daSBryan O'Donoghue err = fdt_splice_string_(fdt, len);
132b908c675SJens Wiklander if (err)
133b908c675SJens Wiklander return err;
134b908c675SJens Wiklander
135*17f326ebSJerome Forissier *allocated = 1;
136*17f326ebSJerome Forissier
137b908c675SJens Wiklander memcpy(new, s, len);
138b908c675SJens Wiklander return (new - strtab);
139b908c675SJens Wiklander }
140b908c675SJens Wiklander
fdt_add_mem_rsv(void * fdt,uint64_t address,uint64_t size)141b908c675SJens Wiklander int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
142b908c675SJens Wiklander {
143b908c675SJens Wiklander struct fdt_reserve_entry *re;
144b908c675SJens Wiklander int err;
145b908c675SJens Wiklander
146*17f326ebSJerome Forissier FDT_RW_PROBE(fdt);
147b908c675SJens Wiklander
14801d6a9daSBryan O'Donoghue re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
14901d6a9daSBryan O'Donoghue err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
150b908c675SJens Wiklander if (err)
151b908c675SJens Wiklander return err;
152b908c675SJens Wiklander
153b908c675SJens Wiklander re->address = cpu_to_fdt64(address);
154b908c675SJens Wiklander re->size = cpu_to_fdt64(size);
155b908c675SJens Wiklander return 0;
156b908c675SJens Wiklander }
157b908c675SJens Wiklander
fdt_del_mem_rsv(void * fdt,int n)158b908c675SJens Wiklander int fdt_del_mem_rsv(void *fdt, int n)
159b908c675SJens Wiklander {
16001d6a9daSBryan O'Donoghue struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
161b908c675SJens Wiklander
162*17f326ebSJerome Forissier FDT_RW_PROBE(fdt);
163b908c675SJens Wiklander
164b908c675SJens Wiklander if (n >= fdt_num_mem_rsv(fdt))
165b908c675SJens Wiklander return -FDT_ERR_NOTFOUND;
166b908c675SJens Wiklander
16701d6a9daSBryan O'Donoghue return fdt_splice_mem_rsv_(fdt, re, 1, 0);
168b908c675SJens Wiklander }
169b908c675SJens Wiklander
fdt_resize_property_(void * fdt,int nodeoffset,const char * name,int len,struct fdt_property ** prop)17001d6a9daSBryan O'Donoghue static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
171b908c675SJens Wiklander int len, struct fdt_property **prop)
172b908c675SJens Wiklander {
173b908c675SJens Wiklander int oldlen;
174b908c675SJens Wiklander int err;
175b908c675SJens Wiklander
176b908c675SJens Wiklander *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
17701d6a9daSBryan O'Donoghue if (!*prop)
178b908c675SJens Wiklander return oldlen;
179b908c675SJens Wiklander
18001d6a9daSBryan O'Donoghue if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
181b908c675SJens Wiklander FDT_TAGALIGN(len))))
182b908c675SJens Wiklander return err;
183b908c675SJens Wiklander
184b908c675SJens Wiklander (*prop)->len = cpu_to_fdt32(len);
185b908c675SJens Wiklander return 0;
186b908c675SJens Wiklander }
187b908c675SJens Wiklander
fdt_add_property_(void * fdt,int nodeoffset,const char * name,int len,struct fdt_property ** prop)18801d6a9daSBryan O'Donoghue static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
189b908c675SJens Wiklander int len, struct fdt_property **prop)
190b908c675SJens Wiklander {
191b908c675SJens Wiklander int proplen;
192b908c675SJens Wiklander int nextoffset;
193b908c675SJens Wiklander int namestroff;
194b908c675SJens Wiklander int err;
195*17f326ebSJerome Forissier int allocated;
196b908c675SJens Wiklander
19701d6a9daSBryan O'Donoghue if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
198b908c675SJens Wiklander return nextoffset;
199b908c675SJens Wiklander
200*17f326ebSJerome Forissier namestroff = fdt_find_add_string_(fdt, name, &allocated);
201b908c675SJens Wiklander if (namestroff < 0)
202b908c675SJens Wiklander return namestroff;
203b908c675SJens Wiklander
20401d6a9daSBryan O'Donoghue *prop = fdt_offset_ptr_w_(fdt, nextoffset);
205b908c675SJens Wiklander proplen = sizeof(**prop) + FDT_TAGALIGN(len);
206b908c675SJens Wiklander
20701d6a9daSBryan O'Donoghue err = fdt_splice_struct_(fdt, *prop, 0, proplen);
208*17f326ebSJerome Forissier if (err) {
209*17f326ebSJerome Forissier if (allocated)
210*17f326ebSJerome Forissier fdt_del_last_string_(fdt, name);
211b908c675SJens Wiklander return err;
212*17f326ebSJerome Forissier }
213b908c675SJens Wiklander
214b908c675SJens Wiklander (*prop)->tag = cpu_to_fdt32(FDT_PROP);
215b908c675SJens Wiklander (*prop)->nameoff = cpu_to_fdt32(namestroff);
216b908c675SJens Wiklander (*prop)->len = cpu_to_fdt32(len);
217b908c675SJens Wiklander return 0;
218b908c675SJens Wiklander }
219b908c675SJens Wiklander
fdt_set_name(void * fdt,int nodeoffset,const char * name)220b908c675SJens Wiklander int fdt_set_name(void *fdt, int nodeoffset, const char *name)
221b908c675SJens Wiklander {
222b908c675SJens Wiklander char *namep;
223b908c675SJens Wiklander int oldlen, newlen;
224b908c675SJens Wiklander int err;
225b908c675SJens Wiklander
226*17f326ebSJerome Forissier FDT_RW_PROBE(fdt);
227b908c675SJens Wiklander
228b908c675SJens Wiklander namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
229b908c675SJens Wiklander if (!namep)
230b908c675SJens Wiklander return oldlen;
231b908c675SJens Wiklander
232b908c675SJens Wiklander newlen = strlen(name);
233b908c675SJens Wiklander
23401d6a9daSBryan O'Donoghue err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
235b908c675SJens Wiklander FDT_TAGALIGN(newlen+1));
236b908c675SJens Wiklander if (err)
237b908c675SJens Wiklander return err;
238b908c675SJens Wiklander
239b908c675SJens Wiklander memcpy(namep, name, newlen+1);
240b908c675SJens Wiklander return 0;
241b908c675SJens Wiklander }
242b908c675SJens Wiklander
fdt_setprop_placeholder(void * fdt,int nodeoffset,const char * name,int len,void ** prop_data)24301d6a9daSBryan O'Donoghue int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
24401d6a9daSBryan O'Donoghue int len, void **prop_data)
245b908c675SJens Wiklander {
246b908c675SJens Wiklander struct fdt_property *prop;
247b908c675SJens Wiklander int err;
248b908c675SJens Wiklander
249*17f326ebSJerome Forissier FDT_RW_PROBE(fdt);
250b908c675SJens Wiklander
25101d6a9daSBryan O'Donoghue err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
252b908c675SJens Wiklander if (err == -FDT_ERR_NOTFOUND)
25301d6a9daSBryan O'Donoghue err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
25401d6a9daSBryan O'Donoghue if (err)
25501d6a9daSBryan O'Donoghue return err;
25601d6a9daSBryan O'Donoghue
25701d6a9daSBryan O'Donoghue *prop_data = prop->data;
25801d6a9daSBryan O'Donoghue return 0;
25901d6a9daSBryan O'Donoghue }
26001d6a9daSBryan O'Donoghue
fdt_setprop(void * fdt,int nodeoffset,const char * name,const void * val,int len)26101d6a9daSBryan O'Donoghue int fdt_setprop(void *fdt, int nodeoffset, const char *name,
26201d6a9daSBryan O'Donoghue const void *val, int len)
26301d6a9daSBryan O'Donoghue {
26401d6a9daSBryan O'Donoghue void *prop_data;
26501d6a9daSBryan O'Donoghue int err;
26601d6a9daSBryan O'Donoghue
26701d6a9daSBryan O'Donoghue err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
268b908c675SJens Wiklander if (err)
269b908c675SJens Wiklander return err;
270b908c675SJens Wiklander
2715f51bfdaSJens Wiklander if (len)
27201d6a9daSBryan O'Donoghue memcpy(prop_data, val, len);
273b908c675SJens Wiklander return 0;
274b908c675SJens Wiklander }
275b908c675SJens Wiklander
fdt_appendprop(void * fdt,int nodeoffset,const char * name,const void * val,int len)276b908c675SJens Wiklander int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
277b908c675SJens Wiklander const void *val, int len)
278b908c675SJens Wiklander {
279b908c675SJens Wiklander struct fdt_property *prop;
280b908c675SJens Wiklander int err, oldlen, newlen;
281b908c675SJens Wiklander
282*17f326ebSJerome Forissier FDT_RW_PROBE(fdt);
283b908c675SJens Wiklander
284b908c675SJens Wiklander prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
285b908c675SJens Wiklander if (prop) {
286b908c675SJens Wiklander newlen = len + oldlen;
28701d6a9daSBryan O'Donoghue err = fdt_splice_struct_(fdt, prop->data,
288b908c675SJens Wiklander FDT_TAGALIGN(oldlen),
289b908c675SJens Wiklander FDT_TAGALIGN(newlen));
290b908c675SJens Wiklander if (err)
291b908c675SJens Wiklander return err;
292b908c675SJens Wiklander prop->len = cpu_to_fdt32(newlen);
293b908c675SJens Wiklander memcpy(prop->data + oldlen, val, len);
294b908c675SJens Wiklander } else {
29501d6a9daSBryan O'Donoghue err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
296b908c675SJens Wiklander if (err)
297b908c675SJens Wiklander return err;
298b908c675SJens Wiklander memcpy(prop->data, val, len);
299b908c675SJens Wiklander }
300b908c675SJens Wiklander return 0;
301b908c675SJens Wiklander }
302b908c675SJens Wiklander
fdt_delprop(void * fdt,int nodeoffset,const char * name)303b908c675SJens Wiklander int fdt_delprop(void *fdt, int nodeoffset, const char *name)
304b908c675SJens Wiklander {
305b908c675SJens Wiklander struct fdt_property *prop;
306b908c675SJens Wiklander int len, proplen;
307b908c675SJens Wiklander
308*17f326ebSJerome Forissier FDT_RW_PROBE(fdt);
309b908c675SJens Wiklander
310b908c675SJens Wiklander prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
311b908c675SJens Wiklander if (!prop)
312b908c675SJens Wiklander return len;
313b908c675SJens Wiklander
314b908c675SJens Wiklander proplen = sizeof(*prop) + FDT_TAGALIGN(len);
31501d6a9daSBryan O'Donoghue return fdt_splice_struct_(fdt, prop, proplen, 0);
316b908c675SJens Wiklander }
317b908c675SJens Wiklander
fdt_add_subnode_namelen(void * fdt,int parentoffset,const char * name,int namelen)318b908c675SJens Wiklander int fdt_add_subnode_namelen(void *fdt, int parentoffset,
319b908c675SJens Wiklander const char *name, int namelen)
320b908c675SJens Wiklander {
321b908c675SJens Wiklander struct fdt_node_header *nh;
322b908c675SJens Wiklander int offset, nextoffset;
323b908c675SJens Wiklander int nodelen;
324b908c675SJens Wiklander int err;
325b908c675SJens Wiklander uint32_t tag;
326b908c675SJens Wiklander fdt32_t *endtag;
327b908c675SJens Wiklander
328*17f326ebSJerome Forissier FDT_RW_PROBE(fdt);
329b908c675SJens Wiklander
330b908c675SJens Wiklander offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
331b908c675SJens Wiklander if (offset >= 0)
332b908c675SJens Wiklander return -FDT_ERR_EXISTS;
333b908c675SJens Wiklander else if (offset != -FDT_ERR_NOTFOUND)
334b908c675SJens Wiklander return offset;
335b908c675SJens Wiklander
336b908c675SJens Wiklander /* Try to place the new node after the parent's properties */
337b908c675SJens Wiklander fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
338b908c675SJens Wiklander do {
339b908c675SJens Wiklander offset = nextoffset;
340b908c675SJens Wiklander tag = fdt_next_tag(fdt, offset, &nextoffset);
341b908c675SJens Wiklander } while ((tag == FDT_PROP) || (tag == FDT_NOP));
342b908c675SJens Wiklander
34301d6a9daSBryan O'Donoghue nh = fdt_offset_ptr_w_(fdt, offset);
344b908c675SJens Wiklander nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
345b908c675SJens Wiklander
34601d6a9daSBryan O'Donoghue err = fdt_splice_struct_(fdt, nh, 0, nodelen);
347b908c675SJens Wiklander if (err)
348b908c675SJens Wiklander return err;
349b908c675SJens Wiklander
350b908c675SJens Wiklander nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
351b908c675SJens Wiklander memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
352b908c675SJens Wiklander memcpy(nh->name, name, namelen);
353b908c675SJens Wiklander endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
354b908c675SJens Wiklander *endtag = cpu_to_fdt32(FDT_END_NODE);
355b908c675SJens Wiklander
356b908c675SJens Wiklander return offset;
357b908c675SJens Wiklander }
358b908c675SJens Wiklander
fdt_add_subnode(void * fdt,int parentoffset,const char * name)359b908c675SJens Wiklander int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
360b908c675SJens Wiklander {
361b908c675SJens Wiklander return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
362b908c675SJens Wiklander }
363b908c675SJens Wiklander
fdt_del_node(void * fdt,int nodeoffset)364b908c675SJens Wiklander int fdt_del_node(void *fdt, int nodeoffset)
365b908c675SJens Wiklander {
366b908c675SJens Wiklander int endoffset;
367b908c675SJens Wiklander
368*17f326ebSJerome Forissier FDT_RW_PROBE(fdt);
369b908c675SJens Wiklander
37001d6a9daSBryan O'Donoghue endoffset = fdt_node_end_offset_(fdt, nodeoffset);
371b908c675SJens Wiklander if (endoffset < 0)
372b908c675SJens Wiklander return endoffset;
373b908c675SJens Wiklander
37401d6a9daSBryan O'Donoghue return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
375b908c675SJens Wiklander endoffset - nodeoffset, 0);
376b908c675SJens Wiklander }
377b908c675SJens Wiklander
fdt_packblocks_(const char * old,char * new,int mem_rsv_size,int struct_size)37801d6a9daSBryan O'Donoghue static void fdt_packblocks_(const char *old, char *new,
379b908c675SJens Wiklander int mem_rsv_size, int struct_size)
380b908c675SJens Wiklander {
381b908c675SJens Wiklander int mem_rsv_off, struct_off, strings_off;
382b908c675SJens Wiklander
383b908c675SJens Wiklander mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
384b908c675SJens Wiklander struct_off = mem_rsv_off + mem_rsv_size;
385b908c675SJens Wiklander strings_off = struct_off + struct_size;
386b908c675SJens Wiklander
387b908c675SJens Wiklander memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
388b908c675SJens Wiklander fdt_set_off_mem_rsvmap(new, mem_rsv_off);
389b908c675SJens Wiklander
390b908c675SJens Wiklander memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
391b908c675SJens Wiklander fdt_set_off_dt_struct(new, struct_off);
392b908c675SJens Wiklander fdt_set_size_dt_struct(new, struct_size);
393b908c675SJens Wiklander
394b908c675SJens Wiklander memmove(new + strings_off, old + fdt_off_dt_strings(old),
395b908c675SJens Wiklander fdt_size_dt_strings(old));
396b908c675SJens Wiklander fdt_set_off_dt_strings(new, strings_off);
397b908c675SJens Wiklander fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
398b908c675SJens Wiklander }
399b908c675SJens Wiklander
fdt_open_into(const void * fdt,void * buf,int bufsize)400b908c675SJens Wiklander int fdt_open_into(const void *fdt, void *buf, int bufsize)
401b908c675SJens Wiklander {
402b908c675SJens Wiklander int err;
403b908c675SJens Wiklander int mem_rsv_size, struct_size;
404b908c675SJens Wiklander int newsize;
405b908c675SJens Wiklander const char *fdtstart = fdt;
406b908c675SJens Wiklander const char *fdtend = fdtstart + fdt_totalsize(fdt);
407b908c675SJens Wiklander char *tmp;
408b908c675SJens Wiklander
409*17f326ebSJerome Forissier FDT_RO_PROBE(fdt);
410b908c675SJens Wiklander
411b908c675SJens Wiklander mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
412b908c675SJens Wiklander * sizeof(struct fdt_reserve_entry);
413b908c675SJens Wiklander
414b908c675SJens Wiklander if (fdt_version(fdt) >= 17) {
415b908c675SJens Wiklander struct_size = fdt_size_dt_struct(fdt);
416b908c675SJens Wiklander } else {
417b908c675SJens Wiklander struct_size = 0;
418b908c675SJens Wiklander while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
419b908c675SJens Wiklander ;
420b908c675SJens Wiklander if (struct_size < 0)
421b908c675SJens Wiklander return struct_size;
422b908c675SJens Wiklander }
423b908c675SJens Wiklander
42401d6a9daSBryan O'Donoghue if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
425b908c675SJens Wiklander /* no further work necessary */
426b908c675SJens Wiklander err = fdt_move(fdt, buf, bufsize);
427b908c675SJens Wiklander if (err)
428b908c675SJens Wiklander return err;
429b908c675SJens Wiklander fdt_set_version(buf, 17);
430b908c675SJens Wiklander fdt_set_size_dt_struct(buf, struct_size);
431b908c675SJens Wiklander fdt_set_totalsize(buf, bufsize);
432b908c675SJens Wiklander return 0;
433b908c675SJens Wiklander }
434b908c675SJens Wiklander
435b908c675SJens Wiklander /* Need to reorder */
436b908c675SJens Wiklander newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
437b908c675SJens Wiklander + struct_size + fdt_size_dt_strings(fdt);
438b908c675SJens Wiklander
439b908c675SJens Wiklander if (bufsize < newsize)
440b908c675SJens Wiklander return -FDT_ERR_NOSPACE;
441b908c675SJens Wiklander
442b908c675SJens Wiklander /* First attempt to build converted tree at beginning of buffer */
443b908c675SJens Wiklander tmp = buf;
444b908c675SJens Wiklander /* But if that overlaps with the old tree... */
445b908c675SJens Wiklander if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
446b908c675SJens Wiklander /* Try right after the old tree instead */
447b908c675SJens Wiklander tmp = (char *)(uintptr_t)fdtend;
448b908c675SJens Wiklander if ((tmp + newsize) > ((char *)buf + bufsize))
449b908c675SJens Wiklander return -FDT_ERR_NOSPACE;
450b908c675SJens Wiklander }
451b908c675SJens Wiklander
45201d6a9daSBryan O'Donoghue fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
453b908c675SJens Wiklander memmove(buf, tmp, newsize);
454b908c675SJens Wiklander
455b908c675SJens Wiklander fdt_set_magic(buf, FDT_MAGIC);
456b908c675SJens Wiklander fdt_set_totalsize(buf, bufsize);
457b908c675SJens Wiklander fdt_set_version(buf, 17);
458b908c675SJens Wiklander fdt_set_last_comp_version(buf, 16);
459b908c675SJens Wiklander fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
460b908c675SJens Wiklander
461b908c675SJens Wiklander return 0;
462b908c675SJens Wiklander }
463b908c675SJens Wiklander
fdt_pack(void * fdt)464b908c675SJens Wiklander int fdt_pack(void *fdt)
465b908c675SJens Wiklander {
466b908c675SJens Wiklander int mem_rsv_size;
467b908c675SJens Wiklander
468*17f326ebSJerome Forissier FDT_RW_PROBE(fdt);
469b908c675SJens Wiklander
470b908c675SJens Wiklander mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
471b908c675SJens Wiklander * sizeof(struct fdt_reserve_entry);
47201d6a9daSBryan O'Donoghue fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
47301d6a9daSBryan O'Donoghue fdt_set_totalsize(fdt, fdt_data_size_(fdt));
474b908c675SJens Wiklander
475b908c675SJens Wiklander return 0;
476b908c675SJens Wiklander }
477