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.eduint fdt_check_header(const void *fdt)
389537Satgutier@umich.edu{
399537Satgutier@umich.edu        if (fdt_magic(fdt) == FDT_MAGIC) {
409537Satgutier@umich.edu                /* Complete tree */
419537Satgutier@umich.edu                if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
429537Satgutier@umich.edu                        return -FDT_ERR_BADVERSION;
439537Satgutier@umich.edu                if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
449537Satgutier@umich.edu                        return -FDT_ERR_BADVERSION;
459537Satgutier@umich.edu        } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
469537Satgutier@umich.edu                /* Unfinished sequential-write blob */
479537Satgutier@umich.edu                if (fdt_size_dt_struct(fdt) == 0)
489537Satgutier@umich.edu                        return -FDT_ERR_BADSTATE;
499537Satgutier@umich.edu        } else {
509537Satgutier@umich.edu                return -FDT_ERR_BADMAGIC;
519537Satgutier@umich.edu        }
529537Satgutier@umich.edu
539537Satgutier@umich.edu        return 0;
549537Satgutier@umich.edu}
559537Satgutier@umich.edu
569537Satgutier@umich.educonst void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
579537Satgutier@umich.edu{
589537Satgutier@umich.edu        const char *p;
599537Satgutier@umich.edu
609537Satgutier@umich.edu        if (fdt_version(fdt) >= 0x11)
619537Satgutier@umich.edu                if (((offset + len) < offset)
629537Satgutier@umich.edu                    || ((offset + len) > fdt_size_dt_struct(fdt)))
639537Satgutier@umich.edu                        return NULL;
649537Satgutier@umich.edu
659537Satgutier@umich.edu        p = _fdt_offset_ptr(fdt, offset);
669537Satgutier@umich.edu
679537Satgutier@umich.edu        if (p + len < p)
689537Satgutier@umich.edu                return NULL;
699537Satgutier@umich.edu        return p;
709537Satgutier@umich.edu}
719537Satgutier@umich.edu
729537Satgutier@umich.eduuint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
739537Satgutier@umich.edu{
749537Satgutier@umich.edu        const fdt32_t *tagp, *lenp;
759537Satgutier@umich.edu        uint32_t tag;
769537Satgutier@umich.edu        int offset = startoffset;
779537Satgutier@umich.edu        const char *p;
789537Satgutier@umich.edu
799537Satgutier@umich.edu        *nextoffset = -FDT_ERR_TRUNCATED;
809537Satgutier@umich.edu        tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
819537Satgutier@umich.edu        if (!tagp)
829537Satgutier@umich.edu                return FDT_END; /* premature end */
839537Satgutier@umich.edu        tag = fdt32_to_cpu(*tagp);
849537Satgutier@umich.edu        offset += FDT_TAGSIZE;
859537Satgutier@umich.edu
869537Satgutier@umich.edu        *nextoffset = -FDT_ERR_BADSTRUCTURE;
879537Satgutier@umich.edu        switch (tag) {
889537Satgutier@umich.edu        case FDT_BEGIN_NODE:
899537Satgutier@umich.edu                /* skip name */
909537Satgutier@umich.edu                do {
919537Satgutier@umich.edu                        p = fdt_offset_ptr(fdt, offset++, 1);
929537Satgutier@umich.edu                } while (p && (*p != '\0'));
939537Satgutier@umich.edu                if (!p)
949537Satgutier@umich.edu                        return FDT_END; /* premature end */
959537Satgutier@umich.edu                break;
969537Satgutier@umich.edu
979537Satgutier@umich.edu        case FDT_PROP:
989537Satgutier@umich.edu                lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
999537Satgutier@umich.edu                if (!lenp)
1009537Satgutier@umich.edu                        return FDT_END; /* premature end */
1019537Satgutier@umich.edu                /* skip-name offset, length and value */
1029537Satgutier@umich.edu                offset += sizeof(struct fdt_property) - FDT_TAGSIZE
1039537Satgutier@umich.edu                        + fdt32_to_cpu(*lenp);
1049537Satgutier@umich.edu                break;
1059537Satgutier@umich.edu
1069537Satgutier@umich.edu        case FDT_END:
1079537Satgutier@umich.edu        case FDT_END_NODE:
1089537Satgutier@umich.edu        case FDT_NOP:
1099537Satgutier@umich.edu                break;
1109537Satgutier@umich.edu
1119537Satgutier@umich.edu        default:
1129537Satgutier@umich.edu                return FDT_END;
1139537Satgutier@umich.edu        }
1149537Satgutier@umich.edu
1159537Satgutier@umich.edu        if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
1169537Satgutier@umich.edu                return FDT_END; /* premature end */
1179537Satgutier@umich.edu
1189537Satgutier@umich.edu        *nextoffset = FDT_TAGALIGN(offset);
1199537Satgutier@umich.edu        return tag;
1209537Satgutier@umich.edu}
1219537Satgutier@umich.edu
1229537Satgutier@umich.eduint _fdt_check_node_offset(const void *fdt, int offset)
1239537Satgutier@umich.edu{
1249537Satgutier@umich.edu        if ((offset < 0) || (offset % FDT_TAGSIZE)
1259537Satgutier@umich.edu            || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
1269537Satgutier@umich.edu                return -FDT_ERR_BADOFFSET;
1279537Satgutier@umich.edu
1289537Satgutier@umich.edu        return offset;
1299537Satgutier@umich.edu}
1309537Satgutier@umich.edu
1319537Satgutier@umich.eduint _fdt_check_prop_offset(const void *fdt, int offset)
1329537Satgutier@umich.edu{
1339537Satgutier@umich.edu        if ((offset < 0) || (offset % FDT_TAGSIZE)
1349537Satgutier@umich.edu            || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
1359537Satgutier@umich.edu                return -FDT_ERR_BADOFFSET;
1369537Satgutier@umich.edu
1379537Satgutier@umich.edu        return offset;
1389537Satgutier@umich.edu}
1399537Satgutier@umich.edu
1409537Satgutier@umich.eduint fdt_next_node(const void *fdt, int offset, int *depth)
1419537Satgutier@umich.edu{
1429537Satgutier@umich.edu        int nextoffset = 0;
1439537Satgutier@umich.edu        uint32_t tag;
1449537Satgutier@umich.edu
1459537Satgutier@umich.edu        if (offset >= 0)
1469537Satgutier@umich.edu                if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
1479537Satgutier@umich.edu                        return nextoffset;
1489537Satgutier@umich.edu
1499537Satgutier@umich.edu        do {
1509537Satgutier@umich.edu                offset = nextoffset;
1519537Satgutier@umich.edu                tag = fdt_next_tag(fdt, offset, &nextoffset);
1529537Satgutier@umich.edu
1539537Satgutier@umich.edu                switch (tag) {
1549537Satgutier@umich.edu                case FDT_PROP:
1559537Satgutier@umich.edu                case FDT_NOP:
1569537Satgutier@umich.edu                        break;
1579537Satgutier@umich.edu
1589537Satgutier@umich.edu                case FDT_BEGIN_NODE:
1599537Satgutier@umich.edu                        if (depth)
1609537Satgutier@umich.edu                                (*depth)++;
1619537Satgutier@umich.edu                        break;
1629537Satgutier@umich.edu
1639537Satgutier@umich.edu                case FDT_END_NODE:
1649537Satgutier@umich.edu                        if (depth && ((--(*depth)) < 0))
1659537Satgutier@umich.edu                                return nextoffset;
1669537Satgutier@umich.edu                        break;
1679537Satgutier@umich.edu
1689537Satgutier@umich.edu                case FDT_END:
1699537Satgutier@umich.edu                        if ((nextoffset >= 0)
1709537Satgutier@umich.edu                            || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
1719537Satgutier@umich.edu                                return -FDT_ERR_NOTFOUND;
1729537Satgutier@umich.edu                        else
1739537Satgutier@umich.edu                                return nextoffset;
1749537Satgutier@umich.edu                }
1759537Satgutier@umich.edu        } while (tag != FDT_BEGIN_NODE);
1769537Satgutier@umich.edu
1779537Satgutier@umich.edu        return offset;
1789537Satgutier@umich.edu}
1799537Satgutier@umich.edu
1809537Satgutier@umich.educonst char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
1819537Satgutier@umich.edu{
1829537Satgutier@umich.edu        int len = strlen(s) + 1;
1839537Satgutier@umich.edu        const char *last = strtab + tabsize - len;
1849537Satgutier@umich.edu        const char *p;
1859537Satgutier@umich.edu
1869537Satgutier@umich.edu        for (p = strtab; p <= last; p++)
1879537Satgutier@umich.edu                if (memcmp(p, s, len) == 0)
1889537Satgutier@umich.edu                        return p;
1899537Satgutier@umich.edu        return NULL;
1909537Satgutier@umich.edu}
1919537Satgutier@umich.edu
1929537Satgutier@umich.eduint fdt_move(const void *fdt, void *buf, int bufsize)
1939537Satgutier@umich.edu{
1949537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
1959537Satgutier@umich.edu
1969537Satgutier@umich.edu        if (fdt_totalsize(fdt) > bufsize)
1979537Satgutier@umich.edu                return -FDT_ERR_NOSPACE;
1989537Satgutier@umich.edu
1999537Satgutier@umich.edu        memmove(buf, fdt, fdt_totalsize(fdt));
2009537Satgutier@umich.edu        return 0;
2019537Satgutier@umich.edu}
202