17ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson/*
27ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson * libfdt - Flat Device Tree manipulation
37ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson * Copyright (C) 2006 David Gibson, IBM Corporation.
47ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson *
5948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson * libfdt is dual licensed: you can use it either under the terms of
6948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson * the GPL, or the BSD license, at your option.
7948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *
8948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *  a) This library is free software; you can redistribute it and/or
9948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     modify it under the terms of the GNU General Public License as
10948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     published by the Free Software Foundation; either version 2 of the
11948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     License, or (at your option) any later version.
12948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *
13948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     This library is distributed in the hope that it will be useful,
14948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     but WITHOUT ANY WARRANTY; without even the implied warranty of
15948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     GNU General Public License for more details.
17948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *
18948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     You should have received a copy of the GNU General Public
19948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     License along with this library; if not, write to the Free
20948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     MA 02110-1301 USA
22948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *
23948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson * Alternatively,
24948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *
25948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *  b) Redistribution and use in source and binary forms, with or
26948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     without modification, are permitted provided that the following
27948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     conditions are met:
28948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *
29948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     1. Redistributions of source code must retain the above
30948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *        copyright notice, this list of conditions and the following
31948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *        disclaimer.
32948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     2. Redistributions in binary form must reproduce the above
33948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *        copyright notice, this list of conditions and the following
34948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *        disclaimer in the documentation and/or other materials
35948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *        provided with the distribution.
36948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *
37948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49948160520884b10f545bec792e0d37c1c14bbf2fDavid Gibson *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
507ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson */
517ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson#include "libfdt_env.h"
527ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
537ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson#include <fdt.h>
547ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson#include <libfdt.h>
557ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
567ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson#include "libfdt_internal.h"
577ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
58b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic int _fdt_blocks_misordered(const void *fdt,
59a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson			      int mem_rsv_size, int struct_size)
60a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson{
61b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
62a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		|| (fdt_off_dt_struct(fdt) <
63a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
64a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		|| (fdt_off_dt_strings(fdt) <
65a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		    (fdt_off_dt_struct(fdt) + struct_size))
66a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		|| (fdt_totalsize(fdt) <
67a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
68a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson}
69a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
70b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic int _fdt_rw_check_header(void *fdt)
717ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
72b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_CHECK_HEADER(fdt);
737ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
744a5df5c026c96f36326d4037a0658d38193e2ca1David Gibson	if (fdt_version(fdt) < 17)
759a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return -FDT_ERR_BADVERSION;
76b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
77b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson				   fdt_size_dt_struct(fdt)))
789a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return -FDT_ERR_BADLAYOUT;
794a5df5c026c96f36326d4037a0658d38193e2ca1David Gibson	if (fdt_version(fdt) > 17)
804a5df5c026c96f36326d4037a0658d38193e2ca1David Gibson		fdt_set_version(fdt, 17);
814a5df5c026c96f36326d4037a0658d38193e2ca1David Gibson
827ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	return 0;
837ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
847ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
85b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson#define FDT_RW_CHECK_HEADER(fdt) \
867ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	{ \
873a584d4760cfc81d21039346b0ce1cb5233e1d72Florian Fainelli		int __err; \
883a584d4760cfc81d21039346b0ce1cb5233e1d72Florian Fainelli		if ((__err = _fdt_rw_check_header(fdt)) != 0) \
893a584d4760cfc81d21039346b0ce1cb5233e1d72Florian Fainelli			return __err; \
907ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	}
917ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
92b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic inline int _fdt_data_size(void *fdt)
937ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
947ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
957ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
967ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
97b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
987ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
9936786db6154533b67d736b414ef63b4457009326David Gibson	char *p = splicepoint;
100b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	char *end = (char *)fdt + _fdt_data_size(fdt);
1017ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
1027ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	if (((p + oldlen) < p) || ((p + oldlen) > end))
1039a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return -FDT_ERR_BADOFFSET;
104d4c7c25c9ed138df8bafbe61097c27c9d2629ee3Courtney Cavin	if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
105d4c7c25c9ed138df8bafbe61097c27c9d2629ee3Courtney Cavin		return -FDT_ERR_BADOFFSET;
10636786db6154533b67d736b414ef63b4457009326David Gibson	if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
1079a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return -FDT_ERR_NOSPACE;
1087ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	memmove(p + newlen, p + oldlen, end - p - oldlen);
1097ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	return 0;
1107ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
1117ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
112b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
113b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson			       int oldn, int newn)
114fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson{
115fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	int delta = (newn - oldn) * sizeof(*p);
116fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	int err;
117b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
118fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	if (err)
119fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson		return err;
1209b91134ba3043deb7689bcee06b78a596647c626David Gibson	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
1219b91134ba3043deb7689bcee06b78a596647c626David Gibson	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
122fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	return 0;
123fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson}
124fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
125b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic int _fdt_splice_struct(void *fdt, void *p,
126b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson			      int oldlen, int newlen)
1277ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
1287ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int delta = newlen - oldlen;
1297ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int err;
1307ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
131b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
1327ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson		return err;
1337ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
1349b91134ba3043deb7689bcee06b78a596647c626David Gibson	fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
1359b91134ba3043deb7689bcee06b78a596647c626David Gibson	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
1367ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	return 0;
1377ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
1387ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
139b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic int _fdt_splice_string(void *fdt, int newlen)
1407ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
14136786db6154533b67d736b414ef63b4457009326David Gibson	void *p = (char *)fdt
14236786db6154533b67d736b414ef63b4457009326David Gibson		+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
1437ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int err;
1447ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
145b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	if ((err = _fdt_splice(fdt, p, 0, newlen)))
1467ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson		return err;
1477ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
1489b91134ba3043deb7689bcee06b78a596647c626David Gibson	fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
1497ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	return 0;
1507ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
1517ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
152b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic int _fdt_find_add_string(void *fdt, const char *s)
1537ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
1547ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
1557ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	const char *p;
1567ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	char *new;
1577ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int len = strlen(s) + 1;
1587ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int err;
1597ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
1607ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
1617ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	if (p)
1627ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson		/* found it */
1637ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson		return (p - strtab);
1647ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
1657ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	new = strtab + fdt_size_dt_strings(fdt);
166b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	err = _fdt_splice_string(fdt, len);
1677ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	if (err)
1689a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return err;
1697ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
1707ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	memcpy(new, s, len);
1717ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	return (new - strtab);
1727ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
1737ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
174fd1bf3a5ae46962528ef89a824261a88830758a2David Gibsonint fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
175fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson{
176fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	struct fdt_reserve_entry *re;
177fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	int err;
178fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
179b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_RW_CHECK_HEADER(fdt);
180fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
181fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
182b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
183fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	if (err)
184fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson		return err;
185fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
186fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	re->address = cpu_to_fdt64(address);
187fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	re->size = cpu_to_fdt64(size);
188fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	return 0;
189fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson}
190fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
191fd1bf3a5ae46962528ef89a824261a88830758a2David Gibsonint fdt_del_mem_rsv(void *fdt, int n)
192fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson{
193fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
194fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
195b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_RW_CHECK_HEADER(fdt);
196aa1baab3cc184169cfb05dfe289b5179c8333e3cDavid Gibson
197fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson	if (n >= fdt_num_mem_rsv(fdt))
198fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson		return -FDT_ERR_NOTFOUND;
199fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
20036fd7331fb11276c09a6affc0d8cd4977f2fe100Masahiro Yamada	return _fdt_splice_mem_rsv(fdt, re, 1, 0);
201fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson}
202fd1bf3a5ae46962528ef89a824261a88830758a2David Gibson
203b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
204b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson				int len, struct fdt_property **prop)
2057ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
2067ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int oldlen;
2077ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int err;
2087ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
209a6c76f923dcc42102fac58375eaca28057811c20David Gibson	*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
210a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson	if (! (*prop))
2119a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return oldlen;
2127ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
213b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
214b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson				      FDT_TAGALIGN(len))))
215a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson		return err;
2167ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
217a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson	(*prop)->len = cpu_to_fdt32(len);
218a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson	return 0;
2197ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
2207ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
221b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
222b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson			     int len, struct fdt_property **prop)
2237ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
2247ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int proplen;
2257ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int nextoffset;
2267ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int namestroff;
2277ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int err;
2287ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
229aa1baab3cc184169cfb05dfe289b5179c8333e3cDavid Gibson	if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
230aa1baab3cc184169cfb05dfe289b5179c8333e3cDavid Gibson		return nextoffset;
2317ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
232b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	namestroff = _fdt_find_add_string(fdt, name);
2337ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	if (namestroff < 0)
2349a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return namestroff;
2357ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
236a6c76f923dcc42102fac58375eaca28057811c20David Gibson	*prop = _fdt_offset_ptr_w(fdt, nextoffset);
237b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	proplen = sizeof(**prop) + FDT_TAGALIGN(len);
2387ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
239b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	err = _fdt_splice_struct(fdt, *prop, 0, proplen);
2407ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	if (err)
241a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson		return err;
2427ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
243a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson	(*prop)->tag = cpu_to_fdt32(FDT_PROP);
244a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson	(*prop)->nameoff = cpu_to_fdt32(namestroff);
245a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson	(*prop)->len = cpu_to_fdt32(len);
246a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson	return 0;
2477ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
2487ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
24982b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibsonint fdt_set_name(void *fdt, int nodeoffset, const char *name)
25082b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson{
25182b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson	char *namep;
25282b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson	int oldlen, newlen;
25382b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson	int err;
25482b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson
255b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_RW_CHECK_HEADER(fdt);
25682b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson
2571409097db8be6ba662e3808654671554c5803bf0David Gibson	namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
25882b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson	if (!namep)
25982b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson		return oldlen;
26082b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson
26182b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson	newlen = strlen(name);
26282b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson
263b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
264b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson				 FDT_TAGALIGN(newlen+1));
26582b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson	if (err)
26682b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson		return err;
26782b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson
26882b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson	memcpy(namep, name, newlen+1);
26982b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson	return 0;
27082b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson}
27182b327d38062cdb4e5628856f9b440ad6c96e7f8David Gibson
27273d60926a05814b8864c86c435e272b386513b0eDavid Gibsonint fdt_setprop(void *fdt, int nodeoffset, const char *name,
2737ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson		const void *val, int len)
2747ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
2757ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	struct fdt_property *prop;
2767ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int err;
2777ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
278b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_RW_CHECK_HEADER(fdt);
2797ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
280b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
2819a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson	if (err == -FDT_ERR_NOTFOUND)
282b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
2837ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	if (err)
2847ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson		return err;
2857ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
28669a1bd6ad3f9272b3db36e6415864a1fb6af4b9dDavid Gibson	if (len)
28769a1bd6ad3f9272b3db36e6415864a1fb6af4b9dDavid Gibson		memcpy(prop->data, val, len);
2887ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	return 0;
2897ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
2907ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
291a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lianint fdt_appendprop(void *fdt, int nodeoffset, const char *name,
292a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian		   const void *val, int len)
293a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian{
294a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian	struct fdt_property *prop;
295a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian	int err, oldlen, newlen;
296a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian
297a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian	FDT_RW_CHECK_HEADER(fdt);
298a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian
299a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian	prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
300a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian	if (prop) {
301a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian		newlen = len + oldlen;
302a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian		err = _fdt_splice_struct(fdt, prop->data,
303a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian					 FDT_TAGALIGN(oldlen),
304a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian					 FDT_TAGALIGN(newlen));
305a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian		if (err)
306a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian			return err;
307a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian		prop->len = cpu_to_fdt32(newlen);
308a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian		memcpy(prop->data + oldlen, val, len);
309a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian	} else {
310a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian		err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
311a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian		if (err)
312a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian			return err;
313a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian		memcpy(prop->data, val, len);
314a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian	}
315a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian	return 0;
316a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian}
317a31e3ef83bfce62d07695355e5f06cd4d0e44b86Minghuan Lian
31873d60926a05814b8864c86c435e272b386513b0eDavid Gibsonint fdt_delprop(void *fdt, int nodeoffset, const char *name)
3197ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
3207ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	struct fdt_property *prop;
3217ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int len, proplen;
3227ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
323b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_RW_CHECK_HEADER(fdt);
3247ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
325a6c76f923dcc42102fac58375eaca28057811c20David Gibson	prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
326a7ee95ded6a0d64c1c259b9c6fea090e19ca81f8David Gibson	if (! prop)
3279a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return len;
3287ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
329b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	proplen = sizeof(*prop) + FDT_TAGALIGN(len);
330b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	return _fdt_splice_struct(fdt, prop, proplen, 0);
3317ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
3327ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
33373d60926a05814b8864c86c435e272b386513b0eDavid Gibsonint fdt_add_subnode_namelen(void *fdt, int parentoffset,
3347ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson			    const char *name, int namelen)
3357ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
3367ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	struct fdt_node_header *nh;
3377ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int offset, nextoffset;
3387ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int nodelen;
3397ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int err;
3407ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	uint32_t tag;
341142419e43c99e88cbe72a760a72cdbf520690eb6Kim Phillips	fdt32_t *endtag;
3427ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
343b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_RW_CHECK_HEADER(fdt);
3447ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
3457ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
3469a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson	if (offset >= 0)
3479a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return -FDT_ERR_EXISTS;
3489a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson	else if (offset != -FDT_ERR_NOTFOUND)
3499a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return offset;
3507ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
3517ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	/* Try to place the new node after the parent's properties */
3523c44c87bdeacc66f46c55090d765a9766475ee50David Gibson	fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
3537ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	do {
3547ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson		offset = nextoffset;
3553c44c87bdeacc66f46c55090d765a9766475ee50David Gibson		tag = fdt_next_tag(fdt, offset, &nextoffset);
356089adb9964a222499eb204198b579c231c59c42fDavid Gibson	} while ((tag == FDT_PROP) || (tag == FDT_NOP));
3577ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
358a6c76f923dcc42102fac58375eaca28057811c20David Gibson	nh = _fdt_offset_ptr_w(fdt, offset);
359b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
360568b569e8961641587cfda8ec23e64cafe45f6d7David Gibson
361b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	err = _fdt_splice_struct(fdt, nh, 0, nodelen);
3627ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	if (err)
3639a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return err;
3647ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
3657ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
366b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
3677ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	memcpy(nh->name, name, namelen);
368142419e43c99e88cbe72a760a72cdbf520690eb6Kim Phillips	endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
3697ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	*endtag = cpu_to_fdt32(FDT_END_NODE);
3707ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
3717ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	return offset;
3727ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
3737ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
37473d60926a05814b8864c86c435e272b386513b0eDavid Gibsonint fdt_add_subnode(void *fdt, int parentoffset, const char *name)
3757ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
3767ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
3777ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
3787ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
37973d60926a05814b8864c86c435e272b386513b0eDavid Gibsonint fdt_del_node(void *fdt, int nodeoffset)
3807ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
3817ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int endoffset;
3827ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
383b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_RW_CHECK_HEADER(fdt);
384394e47208df7e3b22c089745695f41966d100f3eDavid Gibson
3857ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	endoffset = _fdt_node_end_offset(fdt, nodeoffset);
3869a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson	if (endoffset < 0)
3879a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson		return endoffset;
3887ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
389b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
390b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson				  endoffset - nodeoffset, 0);
3917ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
3927ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
393b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibsonstatic void _fdt_packblocks(const char *old, char *new,
394b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson			    int mem_rsv_size, int struct_size)
395a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson{
396a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	int mem_rsv_off, struct_off, strings_off;
397a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
398b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
399a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	struct_off = mem_rsv_off + mem_rsv_size;
400a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	strings_off = struct_off + struct_size;
401a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
40236786db6154533b67d736b414ef63b4457009326David Gibson	memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
40336786db6154533b67d736b414ef63b4457009326David Gibson	fdt_set_off_mem_rsvmap(new, mem_rsv_off);
404a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
40536786db6154533b67d736b414ef63b4457009326David Gibson	memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
40636786db6154533b67d736b414ef63b4457009326David Gibson	fdt_set_off_dt_struct(new, struct_off);
40736786db6154533b67d736b414ef63b4457009326David Gibson	fdt_set_size_dt_struct(new, struct_size);
408a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
40936786db6154533b67d736b414ef63b4457009326David Gibson	memmove(new + strings_off, old + fdt_off_dt_strings(old),
41036786db6154533b67d736b414ef63b4457009326David Gibson		fdt_size_dt_strings(old));
41136786db6154533b67d736b414ef63b4457009326David Gibson	fdt_set_off_dt_strings(new, strings_off);
41236786db6154533b67d736b414ef63b4457009326David Gibson	fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
413a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson}
414a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
415a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibsonint fdt_open_into(const void *fdt, void *buf, int bufsize)
4167ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
4177ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson	int err;
418a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	int mem_rsv_size, struct_size;
419a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	int newsize;
42036786db6154533b67d736b414ef63b4457009326David Gibson	const char *fdtstart = fdt;
42136786db6154533b67d736b414ef63b4457009326David Gibson	const char *fdtend = fdtstart + fdt_totalsize(fdt);
42236786db6154533b67d736b414ef63b4457009326David Gibson	char *tmp;
4237ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
424b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_CHECK_HEADER(fdt);
4257ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
426a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
427a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		* sizeof(struct fdt_reserve_entry);
42873d60926a05814b8864c86c435e272b386513b0eDavid Gibson
429a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	if (fdt_version(fdt) >= 17) {
430a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		struct_size = fdt_size_dt_struct(fdt);
431a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	} else {
432a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		struct_size = 0;
433a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
434a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson			;
4351a020e403048a56ffacb8c6f71aef0944b901757David Gibson		if (struct_size < 0)
4361a020e403048a56ffacb8c6f71aef0944b901757David Gibson			return struct_size;
437a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	}
4387ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
439b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
440a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		/* no further work necessary */
441a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		err = fdt_move(fdt, buf, bufsize);
442a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		if (err)
443a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson			return err;
444a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		fdt_set_version(buf, 17);
445a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		fdt_set_size_dt_struct(buf, struct_size);
446a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		fdt_set_totalsize(buf, bufsize);
447a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		return 0;
448a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	}
4497ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
450a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	/* Need to reorder */
451b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
452a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		+ struct_size + fdt_size_dt_strings(fdt);
453a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
454a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	if (bufsize < newsize)
455a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		return -FDT_ERR_NOSPACE;
456a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
45736786db6154533b67d736b414ef63b4457009326David Gibson	/* First attempt to build converted tree at beginning of buffer */
45836786db6154533b67d736b414ef63b4457009326David Gibson	tmp = buf;
45936786db6154533b67d736b414ef63b4457009326David Gibson	/* But if that overlaps with the old tree... */
46036786db6154533b67d736b414ef63b4457009326David Gibson	if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
46136786db6154533b67d736b414ef63b4457009326David Gibson		/* Try right after the old tree instead */
4621409097db8be6ba662e3808654671554c5803bf0David Gibson		tmp = (char *)(uintptr_t)fdtend;
46336786db6154533b67d736b414ef63b4457009326David Gibson		if ((tmp + newsize) > ((char *)buf + bufsize))
464a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson			return -FDT_ERR_NOSPACE;
465a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	}
466a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
467b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
468a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	memmove(buf, tmp, newsize);
469a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
470a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	fdt_set_magic(buf, FDT_MAGIC);
471a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	fdt_set_totalsize(buf, bufsize);
472a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	fdt_set_version(buf, 17);
473a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	fdt_set_last_comp_version(buf, 16);
474a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
4757ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
4769a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson	return 0;
4777ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
4787ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
47973d60926a05814b8864c86c435e272b386513b0eDavid Gibsonint fdt_pack(void *fdt)
4807ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson{
481a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	int mem_rsv_size;
4827ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
483b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	FDT_RW_CHECK_HEADER(fdt);
4847ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson
485a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson	mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
486a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson		* sizeof(struct fdt_reserve_entry);
487b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
488b6d80a20fc293f3b995c3ce1a6744a5574192125David Gibson	fdt_set_totalsize(fdt, _fdt_data_size(fdt));
489a041dcdc48453f26b76bccdb5e2a1ebb3a0ea987David Gibson
4909a9fdf59913c6d14f1755fe653dc8161ec6b0b7bDavid Gibson	return 0;
4917ba551f96629a5273370329658a6e6b3a87068aaDavid Gibson}
492