/*1* libfdt - Flat Device Tree manipulation2* Copyright (C) 2006 David Gibson, IBM Corporation.3*4* libfdt is dual licensed: you can use it either under the terms of5* the GPL, or the BSD license, at your option.6*7* a) This library is free software; you can redistribute it and/or8* modify it under the terms of the GNU General Public License as9* published by the Free Software Foundation; either version 2 of the10* License, or (at your option) any later version.11*12* This library is distributed in the hope that it will be useful,13* but WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15* GNU General Public License for more details.16*17* You should have received a copy of the GNU General Public18* License along with this library; if not, write to the Free19* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,20* MA 02110-1301 USA21*22* Alternatively,23*24* b) Redistribution and use in source and binary forms, with or25* without modification, are permitted provided that the following26* conditions are met:27*28* 1. Redistributions of source code must retain the above29* copyright notice, this list of conditions and the following30* disclaimer.31* 2. Redistributions in binary form must reproduce the above32* copyright notice, this list of conditions and the following33* disclaimer in the documentation and/or other materials34* provided with the distribution.35*36* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND37* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,38* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF39* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE40* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR41* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,42* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT43* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;44* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)45* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN46* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR47* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,48* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.49*/50#include "libfdt_env.h"5152#include <fdt.h>53#include <libfdt.h>5455#include "libfdt_internal.h"5657int fdt_check_header(const void *fdt)58{59if (fdt_magic(fdt) == FDT_MAGIC) {60/* Complete tree */61if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)62return -FDT_ERR_BADVERSION;63if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)64return -FDT_ERR_BADVERSION;65} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {66/* Unfinished sequential-write blob */67if (fdt_size_dt_struct(fdt) == 0)68return -FDT_ERR_BADSTATE;69} else {70return -FDT_ERR_BADMAGIC;71}7273return 0;74}7576const void *fdt_offset_ptr(const void *fdt, int offset, int len)77{78const char *p;7980if (fdt_version(fdt) >= 0x11)81if (((offset + len) < offset)82|| ((offset + len) > fdt_size_dt_struct(fdt)))83return NULL;8485p = _fdt_offset_ptr(fdt, offset);8687if (p + len < p)88return NULL;89return p;90}9192uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)93{94const uint32_t *tagp, *lenp;95uint32_t tag;96const char *p;9798if (offset % FDT_TAGSIZE)99return -1;100101tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);102if (! tagp)103return FDT_END; /* premature end */104tag = fdt32_to_cpu(*tagp);105offset += FDT_TAGSIZE;106107switch (tag) {108case FDT_BEGIN_NODE:109/* skip name */110do {111p = fdt_offset_ptr(fdt, offset++, 1);112} while (p && (*p != '\0'));113if (! p)114return FDT_END;115break;116case FDT_PROP:117lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));118if (! lenp)119return FDT_END;120/* skip name offset, length and value */121offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);122break;123}124125if (nextoffset)126*nextoffset = FDT_TAGALIGN(offset);127128return tag;129}130131int _fdt_check_node_offset(const void *fdt, int offset)132{133if ((offset < 0) || (offset % FDT_TAGSIZE)134|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))135return -FDT_ERR_BADOFFSET;136137return offset;138}139140int fdt_next_node(const void *fdt, int offset, int *depth)141{142int nextoffset = 0;143uint32_t tag;144145if (offset >= 0)146if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)147return nextoffset;148149do {150offset = nextoffset;151tag = fdt_next_tag(fdt, offset, &nextoffset);152153switch (tag) {154case FDT_PROP:155case FDT_NOP:156break;157158case FDT_BEGIN_NODE:159if (depth)160(*depth)++;161break;162163case FDT_END_NODE:164if (depth)165(*depth)--;166break;167168case FDT_END:169return -FDT_ERR_NOTFOUND;170171default:172return -FDT_ERR_BADSTRUCTURE;173}174} while (tag != FDT_BEGIN_NODE);175176return offset;177}178179const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)180{181int len = strlen(s) + 1;182const char *last = strtab + tabsize - len;183const char *p;184185for (p = strtab; p <= last; p++)186if (memcmp(p, s, len) == 0)187return p;188return NULL;189}190191int fdt_move(const void *fdt, void *buf, int bufsize)192{193FDT_CHECK_HEADER(fdt);194195if (fdt_totalsize(fdt) > bufsize)196return -FDT_ERR_NOSPACE;197198memmove(buf, fdt, fdt_totalsize(fdt));199return 0;200}201202203