uboot/lib/libfdt/fdt.c
<<
>>
Prefs
   1/*
   2 * libfdt - Flat Device Tree manipulation
   3 * Copyright (C) 2006 David Gibson, IBM Corporation.
   4 * SPDX-License-Identifier:     GPL-2.0+ BSD-2-Clause
   5 */
   6#include <libfdt_env.h>
   7
   8#ifndef USE_HOSTCC
   9#include <fdt.h>
  10#include <libfdt.h>
  11#else
  12#include "fdt_host.h"
  13#endif
  14
  15#include "libfdt_internal.h"
  16
  17int fdt_check_header(const void *fdt)
  18{
  19        if (fdt_magic(fdt) == FDT_MAGIC) {
  20                /* Complete tree */
  21                if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
  22                        return -FDT_ERR_BADVERSION;
  23                if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
  24                        return -FDT_ERR_BADVERSION;
  25        } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
  26                /* Unfinished sequential-write blob */
  27                if (fdt_size_dt_struct(fdt) == 0)
  28                        return -FDT_ERR_BADSTATE;
  29        } else {
  30                return -FDT_ERR_BADMAGIC;
  31        }
  32
  33        return 0;
  34}
  35
  36const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
  37{
  38        unsigned absoffset = offset + fdt_off_dt_struct(fdt);
  39
  40        if ((absoffset < offset)
  41            || ((absoffset + len) < absoffset)
  42            || (absoffset + len) > fdt_totalsize(fdt))
  43                return NULL;
  44
  45        if (fdt_version(fdt) >= 0x11)
  46                if (((offset + len) < offset)
  47                    || ((offset + len) > fdt_size_dt_struct(fdt)))
  48                        return NULL;
  49
  50        return _fdt_offset_ptr(fdt, offset);
  51}
  52
  53uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
  54{
  55        const fdt32_t *tagp, *lenp;
  56        uint32_t tag;
  57        int offset = startoffset;
  58        const char *p;
  59
  60        *nextoffset = -FDT_ERR_TRUNCATED;
  61        tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
  62        if (!tagp)
  63                return FDT_END; /* premature end */
  64        tag = fdt32_to_cpu(*tagp);
  65        offset += FDT_TAGSIZE;
  66
  67        *nextoffset = -FDT_ERR_BADSTRUCTURE;
  68        switch (tag) {
  69        case FDT_BEGIN_NODE:
  70                /* skip name */
  71                do {
  72                        p = fdt_offset_ptr(fdt, offset++, 1);
  73                } while (p && (*p != '\0'));
  74                if (!p)
  75                        return FDT_END; /* premature end */
  76                break;
  77
  78        case FDT_PROP:
  79                lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
  80                if (!lenp)
  81                        return FDT_END; /* premature end */
  82                /* skip-name offset, length and value */
  83                offset += sizeof(struct fdt_property) - FDT_TAGSIZE
  84                        + fdt32_to_cpu(*lenp);
  85                break;
  86
  87        case FDT_END:
  88        case FDT_END_NODE:
  89        case FDT_NOP:
  90                break;
  91
  92        default:
  93                return FDT_END;
  94        }
  95
  96        if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
  97                return FDT_END; /* premature end */
  98
  99        *nextoffset = FDT_TAGALIGN(offset);
 100        return tag;
 101}
 102
 103int _fdt_check_node_offset(const void *fdt, int offset)
 104{
 105        if ((offset < 0) || (offset % FDT_TAGSIZE)
 106            || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
 107                return -FDT_ERR_BADOFFSET;
 108
 109        return offset;
 110}
 111
 112int _fdt_check_prop_offset(const void *fdt, int offset)
 113{
 114        if ((offset < 0) || (offset % FDT_TAGSIZE)
 115            || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
 116                return -FDT_ERR_BADOFFSET;
 117
 118        return offset;
 119}
 120
 121int fdt_next_node(const void *fdt, int offset, int *depth)
 122{
 123        int nextoffset = 0;
 124        uint32_t tag;
 125
 126        if (offset >= 0)
 127                if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
 128                        return nextoffset;
 129
 130        do {
 131                offset = nextoffset;
 132                tag = fdt_next_tag(fdt, offset, &nextoffset);
 133
 134                switch (tag) {
 135                case FDT_PROP:
 136                case FDT_NOP:
 137                        break;
 138
 139                case FDT_BEGIN_NODE:
 140                        if (depth)
 141                                (*depth)++;
 142                        break;
 143
 144                case FDT_END_NODE:
 145                        if (depth && ((--(*depth)) < 0))
 146                                return nextoffset;
 147                        break;
 148
 149                case FDT_END:
 150                        if ((nextoffset >= 0)
 151                            || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
 152                                return -FDT_ERR_NOTFOUND;
 153                        else
 154                                return nextoffset;
 155                }
 156        } while (tag != FDT_BEGIN_NODE);
 157
 158        return offset;
 159}
 160
 161int fdt_first_subnode(const void *fdt, int offset)
 162{
 163        int depth = 0;
 164
 165        offset = fdt_next_node(fdt, offset, &depth);
 166        if (offset < 0 || depth != 1)
 167                return -FDT_ERR_NOTFOUND;
 168
 169        return offset;
 170}
 171
 172int fdt_next_subnode(const void *fdt, int offset)
 173{
 174        int depth = 1;
 175
 176        /*
 177         * With respect to the parent, the depth of the next subnode will be
 178         * the same as the last.
 179         */
 180        do {
 181                offset = fdt_next_node(fdt, offset, &depth);
 182                if (offset < 0 || depth < 1)
 183                        return -FDT_ERR_NOTFOUND;
 184        } while (depth > 1);
 185
 186        return offset;
 187}
 188
 189const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
 190{
 191        int len = strlen(s) + 1;
 192        const char *last = strtab + tabsize - len;
 193        const char *p;
 194
 195        for (p = strtab; p <= last; p++)
 196                if (memcmp(p, s, len) == 0)
 197                        return p;
 198        return NULL;
 199}
 200
 201int fdt_move(const void *fdt, void *buf, int bufsize)
 202{
 203        FDT_CHECK_HEADER(fdt);
 204
 205        if (fdt_totalsize(fdt) > bufsize)
 206                return -FDT_ERR_NOSPACE;
 207
 208        memmove(buf, fdt, fdt_totalsize(fdt));
 209        return 0;
 210}
 211