19537Satgutier@umich.edu/*
29537Satgutier@umich.edu * libfdt - Flat Device Tree manipulation
39537Satgutier@umich.edu * Copyright (C) 2006 David Gibson, IBM Corporation.
49537Satgutier@umich.edu *
59537Satgutier@umich.edu *     Redistribution and use in source and binary forms, with or
69537Satgutier@umich.edu *     without modification, are permitted provided that the following
79537Satgutier@umich.edu *     conditions are met:
89537Satgutier@umich.edu *
99537Satgutier@umich.edu *     1. Redistributions of source code must retain the above
109537Satgutier@umich.edu *        copyright notice, this list of conditions and the following
119537Satgutier@umich.edu *        disclaimer.
129537Satgutier@umich.edu *     2. Redistributions in binary form must reproduce the above
139537Satgutier@umich.edu *        copyright notice, this list of conditions and the following
149537Satgutier@umich.edu *        disclaimer in the documentation and/or other materials
159537Satgutier@umich.edu *        provided with the distribution.
169537Satgutier@umich.edu *
179537Satgutier@umich.edu *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
189537Satgutier@umich.edu *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
199537Satgutier@umich.edu *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
209537Satgutier@umich.edu *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
219537Satgutier@umich.edu *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
229537Satgutier@umich.edu *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
239537Satgutier@umich.edu *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
249537Satgutier@umich.edu *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
259537Satgutier@umich.edu *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269537Satgutier@umich.edu *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279537Satgutier@umich.edu *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
289537Satgutier@umich.edu *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
299537Satgutier@umich.edu *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
309537Satgutier@umich.edu */
319537Satgutier@umich.edu#include <fdt.h>
329537Satgutier@umich.edu#include <libfdt.h>
339537Satgutier@umich.edu
349537Satgutier@umich.edu#include "libfdt_env.h"
359537Satgutier@umich.edu#include "libfdt_internal.h"
369537Satgutier@umich.edu
379537Satgutier@umich.edustatic int _fdt_blocks_misordered(const void *fdt,
389537Satgutier@umich.edu                              int mem_rsv_size, int struct_size)
399537Satgutier@umich.edu{
409537Satgutier@umich.edu        return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
419537Satgutier@umich.edu                || (fdt_off_dt_struct(fdt) <
429537Satgutier@umich.edu                    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
439537Satgutier@umich.edu                || (fdt_off_dt_strings(fdt) <
449537Satgutier@umich.edu                    (fdt_off_dt_struct(fdt) + struct_size))
459537Satgutier@umich.edu                || (fdt_totalsize(fdt) <
469537Satgutier@umich.edu                    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
479537Satgutier@umich.edu}
489537Satgutier@umich.edu
499537Satgutier@umich.edustatic int _fdt_rw_check_header(void *fdt)
509537Satgutier@umich.edu{
519537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
529537Satgutier@umich.edu
539537Satgutier@umich.edu        if (fdt_version(fdt) < 17)
549537Satgutier@umich.edu                return -FDT_ERR_BADVERSION;
559537Satgutier@umich.edu        if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
569537Satgutier@umich.edu                                   fdt_size_dt_struct(fdt)))
579537Satgutier@umich.edu                return -FDT_ERR_BADLAYOUT;
589537Satgutier@umich.edu        if (fdt_version(fdt) > 17)
599537Satgutier@umich.edu                fdt_set_version(fdt, 17);
609537Satgutier@umich.edu
619537Satgutier@umich.edu        return 0;
629537Satgutier@umich.edu}
639537Satgutier@umich.edu
649537Satgutier@umich.edu#define FDT_RW_CHECK_HEADER(fdt) \
659537Satgutier@umich.edu        { \
669537Satgutier@umich.edu                int err; \
679537Satgutier@umich.edu                if ((err = _fdt_rw_check_header(fdt)) != 0) \
689537Satgutier@umich.edu                        return err; \
699537Satgutier@umich.edu        }
709537Satgutier@umich.edu
719537Satgutier@umich.edustatic inline int _fdt_data_size(void *fdt)
729537Satgutier@umich.edu{
739537Satgutier@umich.edu        return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
749537Satgutier@umich.edu}
759537Satgutier@umich.edu
769537Satgutier@umich.edustatic int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
779537Satgutier@umich.edu{
789537Satgutier@umich.edu        char *p = splicepoint;
799537Satgutier@umich.edu        char *end = (char *)fdt + _fdt_data_size(fdt);
809537Satgutier@umich.edu
819537Satgutier@umich.edu        if (((p + oldlen) < p) || ((p + oldlen) > end))
829537Satgutier@umich.edu                return -FDT_ERR_BADOFFSET;
839537Satgutier@umich.edu        if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
849537Satgutier@umich.edu                return -FDT_ERR_NOSPACE;
859537Satgutier@umich.edu        memmove(p + newlen, p + oldlen, end - p - oldlen);
869537Satgutier@umich.edu        return 0;
879537Satgutier@umich.edu}
889537Satgutier@umich.edu
899537Satgutier@umich.edustatic int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
909537Satgutier@umich.edu                               int oldn, int newn)
919537Satgutier@umich.edu{
929537Satgutier@umich.edu        int delta = (newn - oldn) * sizeof(*p);
939537Satgutier@umich.edu        int err;
949537Satgutier@umich.edu        err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
959537Satgutier@umich.edu        if (err)
969537Satgutier@umich.edu                return err;
979537Satgutier@umich.edu        fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
989537Satgutier@umich.edu        fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
999537Satgutier@umich.edu        return 0;
1009537Satgutier@umich.edu}
1019537Satgutier@umich.edu
1029537Satgutier@umich.edustatic int _fdt_splice_struct(void *fdt, void *p,
1039537Satgutier@umich.edu                              int oldlen, int newlen)
1049537Satgutier@umich.edu{
1059537Satgutier@umich.edu        int delta = newlen - oldlen;
1069537Satgutier@umich.edu        int err;
1079537Satgutier@umich.edu
1089537Satgutier@umich.edu        if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
1099537Satgutier@umich.edu                return err;
1109537Satgutier@umich.edu
1119537Satgutier@umich.edu        fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
1129537Satgutier@umich.edu        fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
1139537Satgutier@umich.edu        return 0;
1149537Satgutier@umich.edu}
1159537Satgutier@umich.edu
1169537Satgutier@umich.edustatic int _fdt_splice_string(void *fdt, int newlen)
1179537Satgutier@umich.edu{
1189537Satgutier@umich.edu        void *p = (char *)fdt
1199537Satgutier@umich.edu                + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
1209537Satgutier@umich.edu        int err;
1219537Satgutier@umich.edu
1229537Satgutier@umich.edu        if ((err = _fdt_splice(fdt, p, 0, newlen)))
1239537Satgutier@umich.edu                return err;
1249537Satgutier@umich.edu
1259537Satgutier@umich.edu        fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
1269537Satgutier@umich.edu        return 0;
1279537Satgutier@umich.edu}
1289537Satgutier@umich.edu
1299537Satgutier@umich.edustatic int _fdt_find_add_string(void *fdt, const char *s)
1309537Satgutier@umich.edu{
1319537Satgutier@umich.edu        char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
1329537Satgutier@umich.edu        const char *p;
1339537Satgutier@umich.edu        char *new;
1349537Satgutier@umich.edu        int len = strlen(s) + 1;
1359537Satgutier@umich.edu        int err;
1369537Satgutier@umich.edu
1379537Satgutier@umich.edu        p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
1389537Satgutier@umich.edu        if (p)
1399537Satgutier@umich.edu                /* found it */
1409537Satgutier@umich.edu                return (p - strtab);
1419537Satgutier@umich.edu
1429537Satgutier@umich.edu        new = strtab + fdt_size_dt_strings(fdt);
1439537Satgutier@umich.edu        err = _fdt_splice_string(fdt, len);
1449537Satgutier@umich.edu        if (err)
1459537Satgutier@umich.edu                return err;
1469537Satgutier@umich.edu
1479537Satgutier@umich.edu        memcpy(new, s, len);
1489537Satgutier@umich.edu        return (new - strtab);
1499537Satgutier@umich.edu}
1509537Satgutier@umich.edu
1519537Satgutier@umich.eduint fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
1529537Satgutier@umich.edu{
1539537Satgutier@umich.edu        struct fdt_reserve_entry *re;
1549537Satgutier@umich.edu        int err;
1559537Satgutier@umich.edu
1569537Satgutier@umich.edu        FDT_RW_CHECK_HEADER(fdt);
1579537Satgutier@umich.edu
1589537Satgutier@umich.edu        re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
1599537Satgutier@umich.edu        err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
1609537Satgutier@umich.edu        if (err)
1619537Satgutier@umich.edu                return err;
1629537Satgutier@umich.edu
1639537Satgutier@umich.edu        re->address = cpu_to_fdt64(address);
1649537Satgutier@umich.edu        re->size = cpu_to_fdt64(size);
1659537Satgutier@umich.edu        return 0;
1669537Satgutier@umich.edu}
1679537Satgutier@umich.edu
1689537Satgutier@umich.eduint fdt_del_mem_rsv(void *fdt, int n)
1699537Satgutier@umich.edu{
1709537Satgutier@umich.edu        struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
1719537Satgutier@umich.edu        int err;
1729537Satgutier@umich.edu
1739537Satgutier@umich.edu        FDT_RW_CHECK_HEADER(fdt);
1749537Satgutier@umich.edu
1759537Satgutier@umich.edu        if (n >= fdt_num_mem_rsv(fdt))
1769537Satgutier@umich.edu                return -FDT_ERR_NOTFOUND;
1779537Satgutier@umich.edu
1789537Satgutier@umich.edu        err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
1799537Satgutier@umich.edu        if (err)
1809537Satgutier@umich.edu                return err;
1819537Satgutier@umich.edu        return 0;
1829537Satgutier@umich.edu}
1839537Satgutier@umich.edu
1849537Satgutier@umich.edustatic int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
1859537Satgutier@umich.edu                                int len, struct fdt_property **prop)
1869537Satgutier@umich.edu{
1879537Satgutier@umich.edu        int oldlen;
1889537Satgutier@umich.edu        int err;
1899537Satgutier@umich.edu
1909537Satgutier@umich.edu        *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
1919537Satgutier@umich.edu        if (! (*prop))
1929537Satgutier@umich.edu                return oldlen;
1939537Satgutier@umich.edu
1949537Satgutier@umich.edu        if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
1959537Satgutier@umich.edu                                      FDT_TAGALIGN(len))))
1969537Satgutier@umich.edu                return err;
1979537Satgutier@umich.edu
1989537Satgutier@umich.edu        (*prop)->len = cpu_to_fdt32(len);
1999537Satgutier@umich.edu        return 0;
2009537Satgutier@umich.edu}
2019537Satgutier@umich.edu
2029537Satgutier@umich.edustatic int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
2039537Satgutier@umich.edu                             int len, struct fdt_property **prop)
2049537Satgutier@umich.edu{
2059537Satgutier@umich.edu        int proplen;
2069537Satgutier@umich.edu        int nextoffset;
2079537Satgutier@umich.edu        int namestroff;
2089537Satgutier@umich.edu        int err;
2099537Satgutier@umich.edu
2109537Satgutier@umich.edu        if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
2119537Satgutier@umich.edu                return nextoffset;
2129537Satgutier@umich.edu
2139537Satgutier@umich.edu        namestroff = _fdt_find_add_string(fdt, name);
2149537Satgutier@umich.edu        if (namestroff < 0)
2159537Satgutier@umich.edu                return namestroff;
2169537Satgutier@umich.edu
2179537Satgutier@umich.edu        *prop = _fdt_offset_ptr_w(fdt, nextoffset);
2189537Satgutier@umich.edu        proplen = sizeof(**prop) + FDT_TAGALIGN(len);
2199537Satgutier@umich.edu
2209537Satgutier@umich.edu        err = _fdt_splice_struct(fdt, *prop, 0, proplen);
2219537Satgutier@umich.edu        if (err)
2229537Satgutier@umich.edu                return err;
2239537Satgutier@umich.edu
2249537Satgutier@umich.edu        (*prop)->tag = cpu_to_fdt32(FDT_PROP);
2259537Satgutier@umich.edu        (*prop)->nameoff = cpu_to_fdt32(namestroff);
2269537Satgutier@umich.edu        (*prop)->len = cpu_to_fdt32(len);
2279537Satgutier@umich.edu        return 0;
2289537Satgutier@umich.edu}
2299537Satgutier@umich.edu
2309537Satgutier@umich.eduint fdt_set_name(void *fdt, int nodeoffset, const char *name)
2319537Satgutier@umich.edu{
2329537Satgutier@umich.edu        char *namep;
2339537Satgutier@umich.edu        int oldlen, newlen;
2349537Satgutier@umich.edu        int err;
2359537Satgutier@umich.edu
2369537Satgutier@umich.edu        FDT_RW_CHECK_HEADER(fdt);
2379537Satgutier@umich.edu
2389537Satgutier@umich.edu        namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
2399537Satgutier@umich.edu        if (!namep)
2409537Satgutier@umich.edu                return oldlen;
2419537Satgutier@umich.edu
2429537Satgutier@umich.edu        newlen = strlen(name);
2439537Satgutier@umich.edu
2449537Satgutier@umich.edu        err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
2459537Satgutier@umich.edu                                 FDT_TAGALIGN(newlen+1));
2469537Satgutier@umich.edu        if (err)
2479537Satgutier@umich.edu                return err;
2489537Satgutier@umich.edu
2499537Satgutier@umich.edu        memcpy(namep, name, newlen+1);
2509537Satgutier@umich.edu        return 0;
2519537Satgutier@umich.edu}
2529537Satgutier@umich.edu
2539537Satgutier@umich.eduint fdt_setprop(void *fdt, int nodeoffset, const char *name,
2549537Satgutier@umich.edu                const void *val, int len)
2559537Satgutier@umich.edu{
2569537Satgutier@umich.edu        struct fdt_property *prop;
2579537Satgutier@umich.edu        int err;
2589537Satgutier@umich.edu
2599537Satgutier@umich.edu        FDT_RW_CHECK_HEADER(fdt);
2609537Satgutier@umich.edu
2619537Satgutier@umich.edu        err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
2629537Satgutier@umich.edu        if (err == -FDT_ERR_NOTFOUND)
2639537Satgutier@umich.edu                err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
2649537Satgutier@umich.edu        if (err)
2659537Satgutier@umich.edu                return err;
2669537Satgutier@umich.edu
2679537Satgutier@umich.edu        memcpy(prop->data, val, len);
2689537Satgutier@umich.edu        return 0;
2699537Satgutier@umich.edu}
2709537Satgutier@umich.edu
2719537Satgutier@umich.eduint fdt_appendprop(void *fdt, int nodeoffset, const char *name,
2729537Satgutier@umich.edu                   const void *val, int len)
2739537Satgutier@umich.edu{
2749537Satgutier@umich.edu        struct fdt_property *prop;
2759537Satgutier@umich.edu        int err, oldlen, newlen;
2769537Satgutier@umich.edu
2779537Satgutier@umich.edu        FDT_RW_CHECK_HEADER(fdt);
2789537Satgutier@umich.edu
2799537Satgutier@umich.edu        prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
2809537Satgutier@umich.edu        if (prop) {
2819537Satgutier@umich.edu                newlen = len + oldlen;
2829537Satgutier@umich.edu                err = _fdt_splice_struct(fdt, prop->data,
2839537Satgutier@umich.edu                                         FDT_TAGALIGN(oldlen),
2849537Satgutier@umich.edu                                         FDT_TAGALIGN(newlen));
2859537Satgutier@umich.edu                if (err)
2869537Satgutier@umich.edu                        return err;
2879537Satgutier@umich.edu                prop->len = cpu_to_fdt32(newlen);
2889537Satgutier@umich.edu                memcpy(prop->data + oldlen, val, len);
2899537Satgutier@umich.edu        } else {
2909537Satgutier@umich.edu                err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
2919537Satgutier@umich.edu                if (err)
2929537Satgutier@umich.edu                        return err;
2939537Satgutier@umich.edu                memcpy(prop->data, val, len);
2949537Satgutier@umich.edu        }
2959537Satgutier@umich.edu        return 0;
2969537Satgutier@umich.edu}
2979537Satgutier@umich.edu
2989537Satgutier@umich.eduint fdt_delprop(void *fdt, int nodeoffset, const char *name)
2999537Satgutier@umich.edu{
3009537Satgutier@umich.edu        struct fdt_property *prop;
3019537Satgutier@umich.edu        int len, proplen;
3029537Satgutier@umich.edu
3039537Satgutier@umich.edu        FDT_RW_CHECK_HEADER(fdt);
3049537Satgutier@umich.edu
3059537Satgutier@umich.edu        prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
3069537Satgutier@umich.edu        if (! prop)
3079537Satgutier@umich.edu                return len;
3089537Satgutier@umich.edu
3099537Satgutier@umich.edu        proplen = sizeof(*prop) + FDT_TAGALIGN(len);
3109537Satgutier@umich.edu        return _fdt_splice_struct(fdt, prop, proplen, 0);
3119537Satgutier@umich.edu}
3129537Satgutier@umich.edu
3139537Satgutier@umich.eduint fdt_add_subnode_namelen(void *fdt, int parentoffset,
3149537Satgutier@umich.edu                            const char *name, int namelen)
3159537Satgutier@umich.edu{
3169537Satgutier@umich.edu        struct fdt_node_header *nh;
3179537Satgutier@umich.edu        int offset, nextoffset;
3189537Satgutier@umich.edu        int nodelen;
3199537Satgutier@umich.edu        int err;
3209537Satgutier@umich.edu        uint32_t tag;
3219537Satgutier@umich.edu        fdt32_t *endtag;
3229537Satgutier@umich.edu
3239537Satgutier@umich.edu        FDT_RW_CHECK_HEADER(fdt);
3249537Satgutier@umich.edu
3259537Satgutier@umich.edu        offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
3269537Satgutier@umich.edu        if (offset >= 0)
3279537Satgutier@umich.edu                return -FDT_ERR_EXISTS;
3289537Satgutier@umich.edu        else if (offset != -FDT_ERR_NOTFOUND)
3299537Satgutier@umich.edu                return offset;
3309537Satgutier@umich.edu
3319537Satgutier@umich.edu        /* Try to place the new node after the parent's properties */
3329537Satgutier@umich.edu        fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
3339537Satgutier@umich.edu        do {
3349537Satgutier@umich.edu                offset = nextoffset;
3359537Satgutier@umich.edu                tag = fdt_next_tag(fdt, offset, &nextoffset);
3369537Satgutier@umich.edu        } while ((tag == FDT_PROP) || (tag == FDT_NOP));
3379537Satgutier@umich.edu
3389537Satgutier@umich.edu        nh = _fdt_offset_ptr_w(fdt, offset);
3399537Satgutier@umich.edu        nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
3409537Satgutier@umich.edu
3419537Satgutier@umich.edu        err = _fdt_splice_struct(fdt, nh, 0, nodelen);
3429537Satgutier@umich.edu        if (err)
3439537Satgutier@umich.edu                return err;
3449537Satgutier@umich.edu
3459537Satgutier@umich.edu        nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
3469537Satgutier@umich.edu        memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
3479537Satgutier@umich.edu        memcpy(nh->name, name, namelen);
3489537Satgutier@umich.edu        endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
3499537Satgutier@umich.edu        *endtag = cpu_to_fdt32(FDT_END_NODE);
3509537Satgutier@umich.edu
3519537Satgutier@umich.edu        return offset;
3529537Satgutier@umich.edu}
3539537Satgutier@umich.edu
3549537Satgutier@umich.eduint fdt_add_subnode(void *fdt, int parentoffset, const char *name)
3559537Satgutier@umich.edu{
3569537Satgutier@umich.edu        return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
3579537Satgutier@umich.edu}
3589537Satgutier@umich.edu
3599537Satgutier@umich.eduint fdt_del_node(void *fdt, int nodeoffset)
3609537Satgutier@umich.edu{
3619537Satgutier@umich.edu        int endoffset;
3629537Satgutier@umich.edu
3639537Satgutier@umich.edu        FDT_RW_CHECK_HEADER(fdt);
3649537Satgutier@umich.edu
3659537Satgutier@umich.edu        endoffset = _fdt_node_end_offset(fdt, nodeoffset);
3669537Satgutier@umich.edu        if (endoffset < 0)
3679537Satgutier@umich.edu                return endoffset;
3689537Satgutier@umich.edu
3699537Satgutier@umich.edu        return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
3709537Satgutier@umich.edu                                  endoffset - nodeoffset, 0);
3719537Satgutier@umich.edu}
3729537Satgutier@umich.edu
3739537Satgutier@umich.edustatic void _fdt_packblocks(const char *old, char *new,
3749537Satgutier@umich.edu                            int mem_rsv_size, int struct_size)
3759537Satgutier@umich.edu{
3769537Satgutier@umich.edu        int mem_rsv_off, struct_off, strings_off;
3779537Satgutier@umich.edu
3789537Satgutier@umich.edu        mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
3799537Satgutier@umich.edu        struct_off = mem_rsv_off + mem_rsv_size;
3809537Satgutier@umich.edu        strings_off = struct_off + struct_size;
3819537Satgutier@umich.edu
3829537Satgutier@umich.edu        memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
3839537Satgutier@umich.edu        fdt_set_off_mem_rsvmap(new, mem_rsv_off);
3849537Satgutier@umich.edu
3859537Satgutier@umich.edu        memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
3869537Satgutier@umich.edu        fdt_set_off_dt_struct(new, struct_off);
3879537Satgutier@umich.edu        fdt_set_size_dt_struct(new, struct_size);
3889537Satgutier@umich.edu
3899537Satgutier@umich.edu        memmove(new + strings_off, old + fdt_off_dt_strings(old),
3909537Satgutier@umich.edu                fdt_size_dt_strings(old));
3919537Satgutier@umich.edu        fdt_set_off_dt_strings(new, strings_off);
3929537Satgutier@umich.edu        fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
3939537Satgutier@umich.edu}
3949537Satgutier@umich.edu
3959537Satgutier@umich.eduint fdt_open_into(const void *fdt, void *buf, int bufsize)
3969537Satgutier@umich.edu{
3979537Satgutier@umich.edu        int err;
3989537Satgutier@umich.edu        int mem_rsv_size, struct_size;
3999537Satgutier@umich.edu        int newsize;
4009537Satgutier@umich.edu        const char *fdtstart = fdt;
4019537Satgutier@umich.edu        const char *fdtend = fdtstart + fdt_totalsize(fdt);
4029537Satgutier@umich.edu        char *tmp;
4039537Satgutier@umich.edu
4049537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
4059537Satgutier@umich.edu
4069537Satgutier@umich.edu        mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
4079537Satgutier@umich.edu                * sizeof(struct fdt_reserve_entry);
4089537Satgutier@umich.edu
4099537Satgutier@umich.edu        if (fdt_version(fdt) >= 17) {
4109537Satgutier@umich.edu                struct_size = fdt_size_dt_struct(fdt);
4119537Satgutier@umich.edu        } else {
4129537Satgutier@umich.edu                struct_size = 0;
4139537Satgutier@umich.edu                while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
4149537Satgutier@umich.edu                        ;
4159537Satgutier@umich.edu                if (struct_size < 0)
4169537Satgutier@umich.edu                        return struct_size;
4179537Satgutier@umich.edu        }
4189537Satgutier@umich.edu
4199537Satgutier@umich.edu        if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
4209537Satgutier@umich.edu                /* no further work necessary */
4219537Satgutier@umich.edu                err = fdt_move(fdt, buf, bufsize);
4229537Satgutier@umich.edu                if (err)
4239537Satgutier@umich.edu                        return err;
4249537Satgutier@umich.edu                fdt_set_version(buf, 17);
4259537Satgutier@umich.edu                fdt_set_size_dt_struct(buf, struct_size);
4269537Satgutier@umich.edu                fdt_set_totalsize(buf, bufsize);
4279537Satgutier@umich.edu                return 0;
4289537Satgutier@umich.edu        }
4299537Satgutier@umich.edu
4309537Satgutier@umich.edu        /* Need to reorder */
4319537Satgutier@umich.edu        newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
4329537Satgutier@umich.edu                + struct_size + fdt_size_dt_strings(fdt);
4339537Satgutier@umich.edu
4349537Satgutier@umich.edu        if (bufsize < newsize)
4359537Satgutier@umich.edu                return -FDT_ERR_NOSPACE;
4369537Satgutier@umich.edu
4379537Satgutier@umich.edu        /* First attempt to build converted tree at beginning of buffer */
4389537Satgutier@umich.edu        tmp = buf;
4399537Satgutier@umich.edu        /* But if that overlaps with the old tree... */
4409537Satgutier@umich.edu        if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
4419537Satgutier@umich.edu                /* Try right after the old tree instead */
4429537Satgutier@umich.edu                tmp = (char *)(uintptr_t)fdtend;
4439537Satgutier@umich.edu                if ((tmp + newsize) > ((char *)buf + bufsize))
4449537Satgutier@umich.edu                        return -FDT_ERR_NOSPACE;
4459537Satgutier@umich.edu        }
4469537Satgutier@umich.edu
4479537Satgutier@umich.edu        _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
4489537Satgutier@umich.edu        memmove(buf, tmp, newsize);
4499537Satgutier@umich.edu
4509537Satgutier@umich.edu        fdt_set_magic(buf, FDT_MAGIC);
4519537Satgutier@umich.edu        fdt_set_totalsize(buf, bufsize);
4529537Satgutier@umich.edu        fdt_set_version(buf, 17);
4539537Satgutier@umich.edu        fdt_set_last_comp_version(buf, 16);
4549537Satgutier@umich.edu        fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
4559537Satgutier@umich.edu
4569537Satgutier@umich.edu        return 0;
4579537Satgutier@umich.edu}
4589537Satgutier@umich.edu
4599537Satgutier@umich.eduint fdt_pack(void *fdt)
4609537Satgutier@umich.edu{
4619537Satgutier@umich.edu        int mem_rsv_size;
4629537Satgutier@umich.edu
4639537Satgutier@umich.edu        FDT_RW_CHECK_HEADER(fdt);
4649537Satgutier@umich.edu
4659537Satgutier@umich.edu        mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
4669537Satgutier@umich.edu                * sizeof(struct fdt_reserve_entry);
4679537Satgutier@umich.edu        _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
4689537Satgutier@umich.edu        fdt_set_totalsize(fdt, _fdt_data_size(fdt));
4699537Satgutier@umich.edu
4709537Satgutier@umich.edu        return 0;
4719537Satgutier@umich.edu}
472