root/scripts/dtc/libfdt/fdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fdt_ro_probe_
  2. check_off_
  3. check_block_
  4. fdt_header_size_
  5. fdt_check_header
  6. fdt_offset_ptr
  7. fdt_next_tag
  8. fdt_check_node_offset_
  9. fdt_check_prop_offset_
  10. fdt_next_node
  11. fdt_first_subnode
  12. fdt_next_subnode
  13. fdt_find_string_
  14. fdt_move

   1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
   2 /*
   3  * libfdt - Flat Device Tree manipulation
   4  * Copyright (C) 2006 David Gibson, IBM Corporation.
   5  */
   6 #include "libfdt_env.h"
   7 
   8 #include <fdt.h>
   9 #include <libfdt.h>
  10 
  11 #include "libfdt_internal.h"
  12 
  13 /*
  14  * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
  15  * that the given buffer contains what appears to be a flattened
  16  * device tree with sane information in its header.
  17  */
  18 int fdt_ro_probe_(const void *fdt)
  19 {
  20         if (fdt_magic(fdt) == FDT_MAGIC) {
  21                 /* Complete tree */
  22                 if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
  23                         return -FDT_ERR_BADVERSION;
  24                 if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
  25                         return -FDT_ERR_BADVERSION;
  26         } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
  27                 /* Unfinished sequential-write blob */
  28                 if (fdt_size_dt_struct(fdt) == 0)
  29                         return -FDT_ERR_BADSTATE;
  30         } else {
  31                 return -FDT_ERR_BADMAGIC;
  32         }
  33 
  34         return 0;
  35 }
  36 
  37 static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
  38 {
  39         return (off >= hdrsize) && (off <= totalsize);
  40 }
  41 
  42 static int check_block_(uint32_t hdrsize, uint32_t totalsize,
  43                         uint32_t base, uint32_t size)
  44 {
  45         if (!check_off_(hdrsize, totalsize, base))
  46                 return 0; /* block start out of bounds */
  47         if ((base + size) < base)
  48                 return 0; /* overflow */
  49         if (!check_off_(hdrsize, totalsize, base + size))
  50                 return 0; /* block end out of bounds */
  51         return 1;
  52 }
  53 
  54 size_t fdt_header_size_(uint32_t version)
  55 {
  56         if (version <= 1)
  57                 return FDT_V1_SIZE;
  58         else if (version <= 2)
  59                 return FDT_V2_SIZE;
  60         else if (version <= 3)
  61                 return FDT_V3_SIZE;
  62         else if (version <= 16)
  63                 return FDT_V16_SIZE;
  64         else
  65                 return FDT_V17_SIZE;
  66 }
  67 
  68 int fdt_check_header(const void *fdt)
  69 {
  70         size_t hdrsize;
  71 
  72         if (fdt_magic(fdt) != FDT_MAGIC)
  73                 return -FDT_ERR_BADMAGIC;
  74         hdrsize = fdt_header_size(fdt);
  75         if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
  76             || (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
  77                 return -FDT_ERR_BADVERSION;
  78         if (fdt_version(fdt) < fdt_last_comp_version(fdt))
  79                 return -FDT_ERR_BADVERSION;
  80 
  81         if ((fdt_totalsize(fdt) < hdrsize)
  82             || (fdt_totalsize(fdt) > INT_MAX))
  83                 return -FDT_ERR_TRUNCATED;
  84 
  85         /* Bounds check memrsv block */
  86         if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
  87                 return -FDT_ERR_TRUNCATED;
  88 
  89         /* Bounds check structure block */
  90         if (fdt_version(fdt) < 17) {
  91                 if (!check_off_(hdrsize, fdt_totalsize(fdt),
  92                                 fdt_off_dt_struct(fdt)))
  93                         return -FDT_ERR_TRUNCATED;
  94         } else {
  95                 if (!check_block_(hdrsize, fdt_totalsize(fdt),
  96                                   fdt_off_dt_struct(fdt),
  97                                   fdt_size_dt_struct(fdt)))
  98                         return -FDT_ERR_TRUNCATED;
  99         }
 100 
 101         /* Bounds check strings block */
 102         if (!check_block_(hdrsize, fdt_totalsize(fdt),
 103                           fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
 104                 return -FDT_ERR_TRUNCATED;
 105 
 106         return 0;
 107 }
 108 
 109 const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
 110 {
 111         unsigned absoffset = offset + fdt_off_dt_struct(fdt);
 112 
 113         if ((absoffset < offset)
 114             || ((absoffset + len) < absoffset)
 115             || (absoffset + len) > fdt_totalsize(fdt))
 116                 return NULL;
 117 
 118         if (fdt_version(fdt) >= 0x11)
 119                 if (((offset + len) < offset)
 120                     || ((offset + len) > fdt_size_dt_struct(fdt)))
 121                         return NULL;
 122 
 123         return fdt_offset_ptr_(fdt, offset);
 124 }
 125 
 126 uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
 127 {
 128         const fdt32_t *tagp, *lenp;
 129         uint32_t tag;
 130         int offset = startoffset;
 131         const char *p;
 132 
 133         *nextoffset = -FDT_ERR_TRUNCATED;
 134         tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
 135         if (!tagp)
 136                 return FDT_END; /* premature end */
 137         tag = fdt32_to_cpu(*tagp);
 138         offset += FDT_TAGSIZE;
 139 
 140         *nextoffset = -FDT_ERR_BADSTRUCTURE;
 141         switch (tag) {
 142         case FDT_BEGIN_NODE:
 143                 /* skip name */
 144                 do {
 145                         p = fdt_offset_ptr(fdt, offset++, 1);
 146                 } while (p && (*p != '\0'));
 147                 if (!p)
 148                         return FDT_END; /* premature end */
 149                 break;
 150 
 151         case FDT_PROP:
 152                 lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
 153                 if (!lenp)
 154                         return FDT_END; /* premature end */
 155                 /* skip-name offset, length and value */
 156                 offset += sizeof(struct fdt_property) - FDT_TAGSIZE
 157                         + fdt32_to_cpu(*lenp);
 158                 if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
 159                     ((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
 160                         offset += 4;
 161                 break;
 162 
 163         case FDT_END:
 164         case FDT_END_NODE:
 165         case FDT_NOP:
 166                 break;
 167 
 168         default:
 169                 return FDT_END;
 170         }
 171 
 172         if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
 173                 return FDT_END; /* premature end */
 174 
 175         *nextoffset = FDT_TAGALIGN(offset);
 176         return tag;
 177 }
 178 
 179 int fdt_check_node_offset_(const void *fdt, int offset)
 180 {
 181         if ((offset < 0) || (offset % FDT_TAGSIZE)
 182             || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
 183                 return -FDT_ERR_BADOFFSET;
 184 
 185         return offset;
 186 }
 187 
 188 int fdt_check_prop_offset_(const void *fdt, int offset)
 189 {
 190         if ((offset < 0) || (offset % FDT_TAGSIZE)
 191             || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
 192                 return -FDT_ERR_BADOFFSET;
 193 
 194         return offset;
 195 }
 196 
 197 int fdt_next_node(const void *fdt, int offset, int *depth)
 198 {
 199         int nextoffset = 0;
 200         uint32_t tag;
 201 
 202         if (offset >= 0)
 203                 if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
 204                         return nextoffset;
 205 
 206         do {
 207                 offset = nextoffset;
 208                 tag = fdt_next_tag(fdt, offset, &nextoffset);
 209 
 210                 switch (tag) {
 211                 case FDT_PROP:
 212                 case FDT_NOP:
 213                         break;
 214 
 215                 case FDT_BEGIN_NODE:
 216                         if (depth)
 217                                 (*depth)++;
 218                         break;
 219 
 220                 case FDT_END_NODE:
 221                         if (depth && ((--(*depth)) < 0))
 222                                 return nextoffset;
 223                         break;
 224 
 225                 case FDT_END:
 226                         if ((nextoffset >= 0)
 227                             || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
 228                                 return -FDT_ERR_NOTFOUND;
 229                         else
 230                                 return nextoffset;
 231                 }
 232         } while (tag != FDT_BEGIN_NODE);
 233 
 234         return offset;
 235 }
 236 
 237 int fdt_first_subnode(const void *fdt, int offset)
 238 {
 239         int depth = 0;
 240 
 241         offset = fdt_next_node(fdt, offset, &depth);
 242         if (offset < 0 || depth != 1)
 243                 return -FDT_ERR_NOTFOUND;
 244 
 245         return offset;
 246 }
 247 
 248 int fdt_next_subnode(const void *fdt, int offset)
 249 {
 250         int depth = 1;
 251 
 252         /*
 253          * With respect to the parent, the depth of the next subnode will be
 254          * the same as the last.
 255          */
 256         do {
 257                 offset = fdt_next_node(fdt, offset, &depth);
 258                 if (offset < 0 || depth < 1)
 259                         return -FDT_ERR_NOTFOUND;
 260         } while (depth > 1);
 261 
 262         return offset;
 263 }
 264 
 265 const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
 266 {
 267         int len = strlen(s) + 1;
 268         const char *last = strtab + tabsize - len;
 269         const char *p;
 270 
 271         for (p = strtab; p <= last; p++)
 272                 if (memcmp(p, s, len) == 0)
 273                         return p;
 274         return NULL;
 275 }
 276 
 277 int fdt_move(const void *fdt, void *buf, int bufsize)
 278 {
 279         FDT_RO_PROBE(fdt);
 280 
 281         if (fdt_totalsize(fdt) > bufsize)
 282                 return -FDT_ERR_NOSPACE;
 283 
 284         memmove(buf, fdt, fdt_totalsize(fdt));
 285         return 0;
 286 }

/* [<][>][^][v][top][bottom][index][help] */