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