fdt.c revision 204433
143166Snsouch/* 243166Snsouch * libfdt - Flat Device Tree manipulation 343166Snsouch * Copyright (C) 2006 David Gibson, IBM Corporation. 443166Snsouch * 543166Snsouch * libfdt is dual licensed: you can use it either under the terms of 643166Snsouch * the GPL, or the BSD license, at your option. 743166Snsouch * 843166Snsouch * a) This library is free software; you can redistribute it and/or 943166Snsouch * modify it under the terms of the GNU General Public License as 1043166Snsouch * published by the Free Software Foundation; either version 2 of the 1143166Snsouch * License, or (at your option) any later version. 1243166Snsouch * 1343166Snsouch * This library is distributed in the hope that it will be useful, 1443166Snsouch * but WITHOUT ANY WARRANTY; without even the implied warranty of 1543166Snsouch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1643166Snsouch * GNU General Public License for more details. 1743166Snsouch * 1843166Snsouch * You should have received a copy of the GNU General Public 1943166Snsouch * License along with this library; if not, write to the Free 2043166Snsouch * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 2143166Snsouch * MA 02110-1301 USA 2243166Snsouch * 2343166Snsouch * Alternatively, 2443166Snsouch * 2543166Snsouch * b) Redistribution and use in source and binary forms, with or 2643166Snsouch * without modification, are permitted provided that the following 27116192Sobrien * conditions are met: 28116192Sobrien * 29116192Sobrien * 1. Redistributions of source code must retain the above 3043166Snsouch * copyright notice, this list of conditions and the following 3143166Snsouch * disclaimer. 32165951Sjhb * 2. Redistributions in binary form must reproduce the above 3343166Snsouch * copyright notice, this list of conditions and the following 34165951Sjhb * disclaimer in the documentation and/or other materials 3543166Snsouch * provided with the distribution. 36165951Sjhb * 3746651Speter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 38165951Sjhb * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 3943166Snsouch * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 4043166Snsouch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 4143166Snsouch * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 4243166Snsouch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43119288Simp * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44119288Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45272017Srpaulo * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46306814Savg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 4743166Snsouch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 4843166Snsouch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 4943166Snsouch * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50165951Sjhb */ 51165951Sjhb#include "libfdt_env.h" 52165951Sjhb 53165951Sjhb#include <fdt.h> 54165951Sjhb#include <libfdt.h> 55165951Sjhb 56305462Savg#include "libfdt_internal.h" 57165951Sjhb 58197128Savgint fdt_check_header(const void *fdt) 59305462Savg{ 60197128Savg if (fdt_magic(fdt) == FDT_MAGIC) { 61165951Sjhb /* Complete tree */ 6243166Snsouch if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) 63162289Sjhb return -FDT_ERR_BADVERSION; 64165951Sjhb if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) 65165951Sjhb return -FDT_ERR_BADVERSION; 66165951Sjhb } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { 67165951Sjhb /* Unfinished sequential-write blob */ 6843166Snsouch if (fdt_size_dt_struct(fdt) == 0) 6943166Snsouch return -FDT_ERR_BADSTATE; 70165951Sjhb } else { 71165951Sjhb return -FDT_ERR_BADMAGIC; 72165951Sjhb } 73165951Sjhb 74162234Sjhb return 0; 7543166Snsouch} 7643166Snsouch 7743166Snsouchconst void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) 7843166Snsouch{ 7943166Snsouch const char *p; 8043166Snsouch 8143166Snsouch if (fdt_version(fdt) >= 0x11) 8243166Snsouch if (((offset + len) < offset) 8343166Snsouch || ((offset + len) > fdt_size_dt_struct(fdt))) 84162234Sjhb return NULL; 85165951Sjhb 86165951Sjhb p = _fdt_offset_ptr(fdt, offset); 87165951Sjhb 88165951Sjhb if (p + len < p) 89165951Sjhb return NULL; 90162289Sjhb return p; 91165951Sjhb} 92165951Sjhb 93165951Sjhbuint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) 9443166Snsouch{ 95165951Sjhb const uint32_t *tagp, *lenp; 96165951Sjhb uint32_t tag; 97165951Sjhb int offset = startoffset; 98165951Sjhb const char *p; 99165951Sjhb 100165951Sjhb *nextoffset = -FDT_ERR_TRUNCATED; 101165951Sjhb tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); 102165951Sjhb if (!tagp) 103165951Sjhb return FDT_END; /* premature end */ 104234338Savg tag = fdt32_to_cpu(*tagp); 105234338Savg offset += FDT_TAGSIZE; 106234338Savg 107306814Savg *nextoffset = -FDT_ERR_BADSTRUCTURE; 108306120Savg switch (tag) { 109197128Savg case FDT_BEGIN_NODE: 110306814Savg /* skip name */ 111306814Savg do { 112306120Savg p = fdt_offset_ptr(fdt, offset++, 1); 113306120Savg } while (p && (*p != '\0')); 114165951Sjhb if (!p) 115165951Sjhb return FDT_END; /* premature end */ 116165951Sjhb break; 11743166Snsouch 118165951Sjhb case FDT_PROP: 119165951Sjhb lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); 120162289Sjhb if (!lenp) 121305462Savg return FDT_END; /* premature end */ 122306814Savg /* skip-name offset, length and value */ 123305462Savg offset += sizeof(struct fdt_property) - FDT_TAGSIZE 124305462Savg + fdt32_to_cpu(*lenp); 125305462Savg break; 126305462Savg 127305462Savg case FDT_END: 128165951Sjhb case FDT_END_NODE: 129305462Savg case FDT_NOP: 130305462Savg break; 131305462Savg 132305462Savg default: 133305462Savg return FDT_END; 134306814Savg } 135306814Savg 136305462Savg if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) 137305462Savg return FDT_END; /* premature end */ 138305462Savg 139306814Savg *nextoffset = FDT_TAGALIGN(offset); 140305462Savg return tag; 141305462Savg} 142306814Savg 143305462Savgint _fdt_check_node_offset(const void *fdt, int offset) 144305462Savg{ 145305462Savg if ((offset < 0) || (offset % FDT_TAGSIZE) 146305462Savg || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) 147305462Savg return -FDT_ERR_BADOFFSET; 148305462Savg 149305462Savg return offset; 150306814Savg} 151305462Savg 152305462Savgint fdt_next_node(const void *fdt, int offset, int *depth) 153305462Savg{ 154305462Savg int nextoffset = 0; 155305462Savg uint32_t tag; 156306814Savg 157306814Savg if (offset >= 0) 158306814Savg if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) 159306814Savg return nextoffset; 160306814Savg 161306814Savg do { 162306814Savg offset = nextoffset; 163306814Savg tag = fdt_next_tag(fdt, offset, &nextoffset); 164306814Savg 165306814Savg switch (tag) { 166306814Savg case FDT_PROP: 167306814Savg case FDT_NOP: 168306814Savg break; 169306814Savg 170306814Savg case FDT_BEGIN_NODE: 171306814Savg if (depth) 172305462Savg (*depth)++; 173305462Savg break; 174305462Savg 175305462Savg case FDT_END_NODE: 176306814Savg if (depth && ((--(*depth)) < 0)) 177306814Savg return nextoffset; 178305462Savg break; 179305462Savg 180305462Savg case FDT_END: 181306814Savg if ((nextoffset >= 0) 182305462Savg || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) 183305462Savg return -FDT_ERR_NOTFOUND; 184305462Savg else 185305462Savg return nextoffset; 186305462Savg } 187305462Savg } while (tag != FDT_BEGIN_NODE); 188305462Savg 189305462Savg return offset; 190305462Savg} 191305462Savg 192305462Savgconst char *_fdt_find_string(const char *strtab, int tabsize, const char *s) 193306814Savg{ 194305462Savg int len = strlen(s) + 1; 195305462Savg const char *last = strtab + tabsize - len; 196305462Savg const char *p; 197305462Savg 198306122Savg for (p = strtab; p <= last; p++) 199306122Savg if (memcmp(p, s, len) == 0) 200306122Savg return p; 201306122Savg return NULL; 202306122Savg} 203306122Savg 204306122Savgint fdt_move(const void *fdt, void *buf, int bufsize) 205306122Savg{ 206306122Savg FDT_CHECK_HEADER(fdt); 207306122Savg 208306122Savg if (fdt_totalsize(fdt) > bufsize) 209306122Savg return -FDT_ERR_NOSPACE; 210306122Savg 211306122Savg memmove(buf, fdt, fdt_totalsize(fdt)); 212306122Savg return 0; 213306122Savg} 214306122Savg