1d18719a4STom Rini /*
2d18719a4STom Rini * libfdt - Flat Device Tree manipulation
3d18719a4STom Rini * Copyright (C) 2006 David Gibson, IBM Corporation.
4d18719a4STom Rini *
5d18719a4STom Rini * libfdt is dual licensed: you can use it either under the terms of
6d18719a4STom Rini * the GPL, or the BSD license, at your option.
7d18719a4STom Rini *
8d18719a4STom Rini * a) This library is free software; you can redistribute it and/or
9d18719a4STom Rini * modify it under the terms of the GNU General Public License as
10d18719a4STom Rini * published by the Free Software Foundation; either version 2 of the
11d18719a4STom Rini * License, or (at your option) any later version.
12d18719a4STom Rini *
13d18719a4STom Rini * This library is distributed in the hope that it will be useful,
14d18719a4STom Rini * but WITHOUT ANY WARRANTY; without even the implied warranty of
15d18719a4STom Rini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16d18719a4STom Rini * GNU General Public License for more details.
17d18719a4STom Rini *
18d18719a4STom Rini * You should have received a copy of the GNU General Public
19d18719a4STom Rini * License along with this library; if not, write to the Free
20d18719a4STom Rini * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21d18719a4STom Rini * MA 02110-1301 USA
22d18719a4STom Rini *
23d18719a4STom Rini * Alternatively,
24d18719a4STom Rini *
25d18719a4STom Rini * b) Redistribution and use in source and binary forms, with or
26d18719a4STom Rini * without modification, are permitted provided that the following
27d18719a4STom Rini * conditions are met:
28d18719a4STom Rini *
29d18719a4STom Rini * 1. Redistributions of source code must retain the above
30d18719a4STom Rini * copyright notice, this list of conditions and the following
31d18719a4STom Rini * disclaimer.
32d18719a4STom Rini * 2. Redistributions in binary form must reproduce the above
33d18719a4STom Rini * copyright notice, this list of conditions and the following
34d18719a4STom Rini * disclaimer in the documentation and/or other materials
35d18719a4STom Rini * provided with the distribution.
36d18719a4STom Rini *
37d18719a4STom Rini * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38d18719a4STom Rini * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39d18719a4STom Rini * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40d18719a4STom Rini * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41d18719a4STom Rini * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42d18719a4STom Rini * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43d18719a4STom Rini * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44d18719a4STom Rini * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45d18719a4STom Rini * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46d18719a4STom Rini * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47d18719a4STom Rini * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48d18719a4STom Rini * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49d18719a4STom Rini * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50d18719a4STom Rini */
51d18719a4STom Rini #include "libfdt_env.h"
52d18719a4STom Rini
53d18719a4STom Rini #include <fdt.h>
54d18719a4STom Rini #include <libfdt.h>
55d18719a4STom Rini
56d18719a4STom Rini #include "libfdt_internal.h"
57d18719a4STom Rini
_fdt_blocks_misordered(const void * fdt,int mem_rsv_size,int struct_size)58d18719a4STom Rini static int _fdt_blocks_misordered(const void *fdt,
59d18719a4STom Rini int mem_rsv_size, int struct_size)
60d18719a4STom Rini {
61d18719a4STom Rini return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
62d18719a4STom Rini || (fdt_off_dt_struct(fdt) <
63d18719a4STom Rini (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
64d18719a4STom Rini || (fdt_off_dt_strings(fdt) <
65d18719a4STom Rini (fdt_off_dt_struct(fdt) + struct_size))
66d18719a4STom Rini || (fdt_totalsize(fdt) <
67d18719a4STom Rini (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
68d18719a4STom Rini }
69d18719a4STom Rini
_fdt_rw_check_header(void * fdt)70d18719a4STom Rini static int _fdt_rw_check_header(void *fdt)
71d18719a4STom Rini {
72d18719a4STom Rini FDT_CHECK_HEADER(fdt);
73d18719a4STom Rini
74d18719a4STom Rini if (fdt_version(fdt) < 17)
75d18719a4STom Rini return -FDT_ERR_BADVERSION;
76d18719a4STom Rini if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
77d18719a4STom Rini fdt_size_dt_struct(fdt)))
78d18719a4STom Rini return -FDT_ERR_BADLAYOUT;
79d18719a4STom Rini if (fdt_version(fdt) > 17)
80d18719a4STom Rini fdt_set_version(fdt, 17);
81d18719a4STom Rini
82d18719a4STom Rini return 0;
83d18719a4STom Rini }
84d18719a4STom Rini
85d18719a4STom Rini #define FDT_RW_CHECK_HEADER(fdt) \
86d18719a4STom Rini { \
87d18719a4STom Rini int __err; \
88d18719a4STom Rini if ((__err = _fdt_rw_check_header(fdt)) != 0) \
89d18719a4STom Rini return __err; \
90d18719a4STom Rini }
91d18719a4STom Rini
_fdt_data_size(void * fdt)92d18719a4STom Rini static inline int _fdt_data_size(void *fdt)
93d18719a4STom Rini {
94d18719a4STom Rini return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
95d18719a4STom Rini }
96d18719a4STom Rini
_fdt_splice(void * fdt,void * splicepoint,int oldlen,int newlen)97d18719a4STom Rini static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
98d18719a4STom Rini {
99d18719a4STom Rini char *p = splicepoint;
100d18719a4STom Rini char *end = (char *)fdt + _fdt_data_size(fdt);
101d18719a4STom Rini
102d18719a4STom Rini if (((p + oldlen) < p) || ((p + oldlen) > end))
103d18719a4STom Rini return -FDT_ERR_BADOFFSET;
104d18719a4STom Rini if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
105d18719a4STom Rini return -FDT_ERR_BADOFFSET;
106d18719a4STom Rini if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
107d18719a4STom Rini return -FDT_ERR_NOSPACE;
108d18719a4STom Rini memmove(p + newlen, p + oldlen, end - p - oldlen);
109d18719a4STom Rini return 0;
110d18719a4STom Rini }
111d18719a4STom Rini
_fdt_splice_mem_rsv(void * fdt,struct fdt_reserve_entry * p,int oldn,int newn)112d18719a4STom Rini static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
113d18719a4STom Rini int oldn, int newn)
114d18719a4STom Rini {
115d18719a4STom Rini int delta = (newn - oldn) * sizeof(*p);
116d18719a4STom Rini int err;
117d18719a4STom Rini err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
118d18719a4STom Rini if (err)
119d18719a4STom Rini return err;
120d18719a4STom Rini fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
121d18719a4STom Rini fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
122d18719a4STom Rini return 0;
123d18719a4STom Rini }
124d18719a4STom Rini
_fdt_splice_struct(void * fdt,void * p,int oldlen,int newlen)125d18719a4STom Rini static int _fdt_splice_struct(void *fdt, void *p,
126d18719a4STom Rini int oldlen, int newlen)
127d18719a4STom Rini {
128d18719a4STom Rini int delta = newlen - oldlen;
129d18719a4STom Rini int err;
130d18719a4STom Rini
131d18719a4STom Rini if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
132d18719a4STom Rini return err;
133d18719a4STom Rini
134d18719a4STom Rini fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
135d18719a4STom Rini fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
136d18719a4STom Rini return 0;
137d18719a4STom Rini }
138d18719a4STom Rini
_fdt_splice_string(void * fdt,int newlen)139d18719a4STom Rini static int _fdt_splice_string(void *fdt, int newlen)
140d18719a4STom Rini {
141d18719a4STom Rini void *p = (char *)fdt
142d18719a4STom Rini + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
143d18719a4STom Rini int err;
144d18719a4STom Rini
145d18719a4STom Rini if ((err = _fdt_splice(fdt, p, 0, newlen)))
146d18719a4STom Rini return err;
147d18719a4STom Rini
148d18719a4STom Rini fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
149d18719a4STom Rini return 0;
150d18719a4STom Rini }
151d18719a4STom Rini
_fdt_find_add_string(void * fdt,const char * s)152d18719a4STom Rini static int _fdt_find_add_string(void *fdt, const char *s)
153d18719a4STom Rini {
154d18719a4STom Rini char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
155d18719a4STom Rini const char *p;
156d18719a4STom Rini char *new;
157d18719a4STom Rini int len = strlen(s) + 1;
158d18719a4STom Rini int err;
159d18719a4STom Rini
160d18719a4STom Rini p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
161d18719a4STom Rini if (p)
162d18719a4STom Rini /* found it */
163d18719a4STom Rini return (p - strtab);
164d18719a4STom Rini
165d18719a4STom Rini new = strtab + fdt_size_dt_strings(fdt);
166d18719a4STom Rini err = _fdt_splice_string(fdt, len);
167d18719a4STom Rini if (err)
168d18719a4STom Rini return err;
169d18719a4STom Rini
170d18719a4STom Rini memcpy(new, s, len);
171d18719a4STom Rini return (new - strtab);
172d18719a4STom Rini }
173d18719a4STom Rini
fdt_add_mem_rsv(void * fdt,uint64_t address,uint64_t size)174d18719a4STom Rini int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
175d18719a4STom Rini {
176d18719a4STom Rini struct fdt_reserve_entry *re;
177d18719a4STom Rini int err;
178d18719a4STom Rini
179d18719a4STom Rini FDT_RW_CHECK_HEADER(fdt);
180d18719a4STom Rini
181d18719a4STom Rini re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
182d18719a4STom Rini err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
183d18719a4STom Rini if (err)
184d18719a4STom Rini return err;
185d18719a4STom Rini
186d18719a4STom Rini re->address = cpu_to_fdt64(address);
187d18719a4STom Rini re->size = cpu_to_fdt64(size);
188d18719a4STom Rini return 0;
189d18719a4STom Rini }
190d18719a4STom Rini
fdt_del_mem_rsv(void * fdt,int n)191d18719a4STom Rini int fdt_del_mem_rsv(void *fdt, int n)
192d18719a4STom Rini {
193d18719a4STom Rini struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
194d18719a4STom Rini
195d18719a4STom Rini FDT_RW_CHECK_HEADER(fdt);
196d18719a4STom Rini
197d18719a4STom Rini if (n >= fdt_num_mem_rsv(fdt))
198d18719a4STom Rini return -FDT_ERR_NOTFOUND;
199d18719a4STom Rini
200d18719a4STom Rini return _fdt_splice_mem_rsv(fdt, re, 1, 0);
201d18719a4STom Rini }
202d18719a4STom Rini
_fdt_resize_property(void * fdt,int nodeoffset,const char * name,int len,struct fdt_property ** prop)203d18719a4STom Rini static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
204d18719a4STom Rini int len, struct fdt_property **prop)
205d18719a4STom Rini {
206d18719a4STom Rini int oldlen;
207d18719a4STom Rini int err;
208d18719a4STom Rini
209d18719a4STom Rini *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
210*d7857e40STom Rini if (!*prop)
211d18719a4STom Rini return oldlen;
212d18719a4STom Rini
213d18719a4STom Rini if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
214d18719a4STom Rini FDT_TAGALIGN(len))))
215d18719a4STom Rini return err;
216d18719a4STom Rini
217d18719a4STom Rini (*prop)->len = cpu_to_fdt32(len);
218d18719a4STom Rini return 0;
219d18719a4STom Rini }
220d18719a4STom Rini
_fdt_add_property(void * fdt,int nodeoffset,const char * name,int len,struct fdt_property ** prop)221d18719a4STom Rini static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
222d18719a4STom Rini int len, struct fdt_property **prop)
223d18719a4STom Rini {
224d18719a4STom Rini int proplen;
225d18719a4STom Rini int nextoffset;
226d18719a4STom Rini int namestroff;
227d18719a4STom Rini int err;
228d18719a4STom Rini
229d18719a4STom Rini if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
230d18719a4STom Rini return nextoffset;
231d18719a4STom Rini
232d18719a4STom Rini namestroff = _fdt_find_add_string(fdt, name);
233d18719a4STom Rini if (namestroff < 0)
234d18719a4STom Rini return namestroff;
235d18719a4STom Rini
236d18719a4STom Rini *prop = _fdt_offset_ptr_w(fdt, nextoffset);
237d18719a4STom Rini proplen = sizeof(**prop) + FDT_TAGALIGN(len);
238d18719a4STom Rini
239d18719a4STom Rini err = _fdt_splice_struct(fdt, *prop, 0, proplen);
240d18719a4STom Rini if (err)
241d18719a4STom Rini return err;
242d18719a4STom Rini
243d18719a4STom Rini (*prop)->tag = cpu_to_fdt32(FDT_PROP);
244d18719a4STom Rini (*prop)->nameoff = cpu_to_fdt32(namestroff);
245d18719a4STom Rini (*prop)->len = cpu_to_fdt32(len);
246d18719a4STom Rini return 0;
247d18719a4STom Rini }
248d18719a4STom Rini
fdt_set_name(void * fdt,int nodeoffset,const char * name)249d18719a4STom Rini int fdt_set_name(void *fdt, int nodeoffset, const char *name)
250d18719a4STom Rini {
251d18719a4STom Rini char *namep;
252d18719a4STom Rini int oldlen, newlen;
253d18719a4STom Rini int err;
254d18719a4STom Rini
255d18719a4STom Rini FDT_RW_CHECK_HEADER(fdt);
256d18719a4STom Rini
257d18719a4STom Rini namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
258d18719a4STom Rini if (!namep)
259d18719a4STom Rini return oldlen;
260d18719a4STom Rini
261d18719a4STom Rini newlen = strlen(name);
262d18719a4STom Rini
263d18719a4STom Rini err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
264d18719a4STom Rini FDT_TAGALIGN(newlen+1));
265d18719a4STom Rini if (err)
266d18719a4STom Rini return err;
267d18719a4STom Rini
268d18719a4STom Rini memcpy(namep, name, newlen+1);
269d18719a4STom Rini return 0;
270d18719a4STom Rini }
271d18719a4STom Rini
fdt_setprop_placeholder(void * fdt,int nodeoffset,const char * name,int len,void ** prop_data)272*d7857e40STom Rini int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
273*d7857e40STom Rini int len, void **prop_data)
274d18719a4STom Rini {
275d18719a4STom Rini struct fdt_property *prop;
276d18719a4STom Rini int err;
277d18719a4STom Rini
278d18719a4STom Rini FDT_RW_CHECK_HEADER(fdt);
279d18719a4STom Rini
280d18719a4STom Rini err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
281d18719a4STom Rini if (err == -FDT_ERR_NOTFOUND)
282d18719a4STom Rini err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
283d18719a4STom Rini if (err)
284d18719a4STom Rini return err;
285d18719a4STom Rini
286*d7857e40STom Rini *prop_data = prop->data;
287*d7857e40STom Rini return 0;
288*d7857e40STom Rini }
289*d7857e40STom Rini
fdt_setprop(void * fdt,int nodeoffset,const char * name,const void * val,int len)290*d7857e40STom Rini int fdt_setprop(void *fdt, int nodeoffset, const char *name,
291*d7857e40STom Rini const void *val, int len)
292*d7857e40STom Rini {
293*d7857e40STom Rini void *prop_data;
294*d7857e40STom Rini int err;
295*d7857e40STom Rini
296*d7857e40STom Rini err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
297*d7857e40STom Rini if (err)
298*d7857e40STom Rini return err;
299*d7857e40STom Rini
300d18719a4STom Rini if (len)
301*d7857e40STom Rini memcpy(prop_data, val, len);
302d18719a4STom Rini return 0;
303d18719a4STom Rini }
304d18719a4STom Rini
fdt_appendprop(void * fdt,int nodeoffset,const char * name,const void * val,int len)305d18719a4STom Rini int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
306d18719a4STom Rini const void *val, int len)
307d18719a4STom Rini {
308d18719a4STom Rini struct fdt_property *prop;
309d18719a4STom Rini int err, oldlen, newlen;
310d18719a4STom Rini
311d18719a4STom Rini FDT_RW_CHECK_HEADER(fdt);
312d18719a4STom Rini
313d18719a4STom Rini prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
314d18719a4STom Rini if (prop) {
315d18719a4STom Rini newlen = len + oldlen;
316d18719a4STom Rini err = _fdt_splice_struct(fdt, prop->data,
317d18719a4STom Rini FDT_TAGALIGN(oldlen),
318d18719a4STom Rini FDT_TAGALIGN(newlen));
319d18719a4STom Rini if (err)
320d18719a4STom Rini return err;
321d18719a4STom Rini prop->len = cpu_to_fdt32(newlen);
322d18719a4STom Rini memcpy(prop->data + oldlen, val, len);
323d18719a4STom Rini } else {
324d18719a4STom Rini err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
325d18719a4STom Rini if (err)
326d18719a4STom Rini return err;
327d18719a4STom Rini memcpy(prop->data, val, len);
328d18719a4STom Rini }
329d18719a4STom Rini return 0;
330d18719a4STom Rini }
331d18719a4STom Rini
fdt_delprop(void * fdt,int nodeoffset,const char * name)332d18719a4STom Rini int fdt_delprop(void *fdt, int nodeoffset, const char *name)
333d18719a4STom Rini {
334d18719a4STom Rini struct fdt_property *prop;
335d18719a4STom Rini int len, proplen;
336d18719a4STom Rini
337d18719a4STom Rini FDT_RW_CHECK_HEADER(fdt);
338d18719a4STom Rini
339d18719a4STom Rini prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
340d18719a4STom Rini if (!prop)
341d18719a4STom Rini return len;
342d18719a4STom Rini
343d18719a4STom Rini proplen = sizeof(*prop) + FDT_TAGALIGN(len);
344d18719a4STom Rini return _fdt_splice_struct(fdt, prop, proplen, 0);
345d18719a4STom Rini }
346d18719a4STom Rini
fdt_add_subnode_namelen(void * fdt,int parentoffset,const char * name,int namelen)347d18719a4STom Rini int fdt_add_subnode_namelen(void *fdt, int parentoffset,
348d18719a4STom Rini const char *name, int namelen)
349d18719a4STom Rini {
350d18719a4STom Rini struct fdt_node_header *nh;
351d18719a4STom Rini int offset, nextoffset;
352d18719a4STom Rini int nodelen;
353d18719a4STom Rini int err;
354d18719a4STom Rini uint32_t tag;
355d18719a4STom Rini fdt32_t *endtag;
356d18719a4STom Rini
357d18719a4STom Rini FDT_RW_CHECK_HEADER(fdt);
358d18719a4STom Rini
359d18719a4STom Rini offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
360d18719a4STom Rini if (offset >= 0)
361d18719a4STom Rini return -FDT_ERR_EXISTS;
362d18719a4STom Rini else if (offset != -FDT_ERR_NOTFOUND)
363d18719a4STom Rini return offset;
364d18719a4STom Rini
365d18719a4STom Rini /* Try to place the new node after the parent's properties */
366d18719a4STom Rini fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
367d18719a4STom Rini do {
368d18719a4STom Rini offset = nextoffset;
369d18719a4STom Rini tag = fdt_next_tag(fdt, offset, &nextoffset);
370d18719a4STom Rini } while ((tag == FDT_PROP) || (tag == FDT_NOP));
371d18719a4STom Rini
372d18719a4STom Rini nh = _fdt_offset_ptr_w(fdt, offset);
373d18719a4STom Rini nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
374d18719a4STom Rini
375d18719a4STom Rini err = _fdt_splice_struct(fdt, nh, 0, nodelen);
376d18719a4STom Rini if (err)
377d18719a4STom Rini return err;
378d18719a4STom Rini
379d18719a4STom Rini nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
380d18719a4STom Rini memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
381d18719a4STom Rini memcpy(nh->name, name, namelen);
382d18719a4STom Rini endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
383d18719a4STom Rini *endtag = cpu_to_fdt32(FDT_END_NODE);
384d18719a4STom Rini
385d18719a4STom Rini return offset;
386d18719a4STom Rini }
387d18719a4STom Rini
fdt_add_subnode(void * fdt,int parentoffset,const char * name)388d18719a4STom Rini int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
389d18719a4STom Rini {
390d18719a4STom Rini return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
391d18719a4STom Rini }
392d18719a4STom Rini
fdt_del_node(void * fdt,int nodeoffset)393d18719a4STom Rini int fdt_del_node(void *fdt, int nodeoffset)
394d18719a4STom Rini {
395d18719a4STom Rini int endoffset;
396d18719a4STom Rini
397d18719a4STom Rini FDT_RW_CHECK_HEADER(fdt);
398d18719a4STom Rini
399d18719a4STom Rini endoffset = _fdt_node_end_offset(fdt, nodeoffset);
400d18719a4STom Rini if (endoffset < 0)
401d18719a4STom Rini return endoffset;
402d18719a4STom Rini
403d18719a4STom Rini return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
404d18719a4STom Rini endoffset - nodeoffset, 0);
405d18719a4STom Rini }
406d18719a4STom Rini
_fdt_packblocks(const char * old,char * new,int mem_rsv_size,int struct_size)407d18719a4STom Rini static void _fdt_packblocks(const char *old, char *new,
408d18719a4STom Rini int mem_rsv_size, int struct_size)
409d18719a4STom Rini {
410d18719a4STom Rini int mem_rsv_off, struct_off, strings_off;
411d18719a4STom Rini
412d18719a4STom Rini mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
413d18719a4STom Rini struct_off = mem_rsv_off + mem_rsv_size;
414d18719a4STom Rini strings_off = struct_off + struct_size;
415d18719a4STom Rini
416d18719a4STom Rini memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
417d18719a4STom Rini fdt_set_off_mem_rsvmap(new, mem_rsv_off);
418d18719a4STom Rini
419d18719a4STom Rini memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
420d18719a4STom Rini fdt_set_off_dt_struct(new, struct_off);
421d18719a4STom Rini fdt_set_size_dt_struct(new, struct_size);
422d18719a4STom Rini
423d18719a4STom Rini memmove(new + strings_off, old + fdt_off_dt_strings(old),
424d18719a4STom Rini fdt_size_dt_strings(old));
425d18719a4STom Rini fdt_set_off_dt_strings(new, strings_off);
426d18719a4STom Rini fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
427d18719a4STom Rini }
428d18719a4STom Rini
fdt_open_into(const void * fdt,void * buf,int bufsize)429d18719a4STom Rini int fdt_open_into(const void *fdt, void *buf, int bufsize)
430d18719a4STom Rini {
431d18719a4STom Rini int err;
432d18719a4STom Rini int mem_rsv_size, struct_size;
433d18719a4STom Rini int newsize;
434d18719a4STom Rini const char *fdtstart = fdt;
435d18719a4STom Rini const char *fdtend = fdtstart + fdt_totalsize(fdt);
436d18719a4STom Rini char *tmp;
437d18719a4STom Rini
438d18719a4STom Rini FDT_CHECK_HEADER(fdt);
439d18719a4STom Rini
440d18719a4STom Rini mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
441d18719a4STom Rini * sizeof(struct fdt_reserve_entry);
442d18719a4STom Rini
443d18719a4STom Rini if (fdt_version(fdt) >= 17) {
444d18719a4STom Rini struct_size = fdt_size_dt_struct(fdt);
445d18719a4STom Rini } else {
446d18719a4STom Rini struct_size = 0;
447d18719a4STom Rini while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
448d18719a4STom Rini ;
449d18719a4STom Rini if (struct_size < 0)
450d18719a4STom Rini return struct_size;
451d18719a4STom Rini }
452d18719a4STom Rini
453d18719a4STom Rini if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
454d18719a4STom Rini /* no further work necessary */
455d18719a4STom Rini err = fdt_move(fdt, buf, bufsize);
456d18719a4STom Rini if (err)
457d18719a4STom Rini return err;
458d18719a4STom Rini fdt_set_version(buf, 17);
459d18719a4STom Rini fdt_set_size_dt_struct(buf, struct_size);
460d18719a4STom Rini fdt_set_totalsize(buf, bufsize);
461d18719a4STom Rini return 0;
462d18719a4STom Rini }
463d18719a4STom Rini
464d18719a4STom Rini /* Need to reorder */
465d18719a4STom Rini newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
466d18719a4STom Rini + struct_size + fdt_size_dt_strings(fdt);
467d18719a4STom Rini
468d18719a4STom Rini if (bufsize < newsize)
469d18719a4STom Rini return -FDT_ERR_NOSPACE;
470d18719a4STom Rini
471d18719a4STom Rini /* First attempt to build converted tree at beginning of buffer */
472d18719a4STom Rini tmp = buf;
473d18719a4STom Rini /* But if that overlaps with the old tree... */
474d18719a4STom Rini if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
475d18719a4STom Rini /* Try right after the old tree instead */
476d18719a4STom Rini tmp = (char *)(uintptr_t)fdtend;
477d18719a4STom Rini if ((tmp + newsize) > ((char *)buf + bufsize))
478d18719a4STom Rini return -FDT_ERR_NOSPACE;
479d18719a4STom Rini }
480d18719a4STom Rini
481d18719a4STom Rini _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
482d18719a4STom Rini memmove(buf, tmp, newsize);
483d18719a4STom Rini
484d18719a4STom Rini fdt_set_magic(buf, FDT_MAGIC);
485d18719a4STom Rini fdt_set_totalsize(buf, bufsize);
486d18719a4STom Rini fdt_set_version(buf, 17);
487d18719a4STom Rini fdt_set_last_comp_version(buf, 16);
488d18719a4STom Rini fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
489d18719a4STom Rini
490d18719a4STom Rini return 0;
491d18719a4STom Rini }
492d18719a4STom Rini
fdt_pack(void * fdt)493d18719a4STom Rini int fdt_pack(void *fdt)
494d18719a4STom Rini {
495d18719a4STom Rini int mem_rsv_size;
496d18719a4STom Rini
497d18719a4STom Rini FDT_RW_CHECK_HEADER(fdt);
498d18719a4STom Rini
499d18719a4STom Rini mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
500d18719a4STom Rini * sizeof(struct fdt_reserve_entry);
501d18719a4STom Rini _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
502d18719a4STom Rini fdt_set_totalsize(fdt, _fdt_data_size(fdt));
503d18719a4STom Rini
504d18719a4STom Rini return 0;
505d18719a4STom Rini }
506