root/scripts/dtc/libfdt/fdt_ro.c

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

DEFINITIONS

This source file includes following definitions.
  1. fdt_nodename_eq_
  2. fdt_get_string
  3. fdt_string
  4. fdt_string_eq_
  5. fdt_find_max_phandle
  6. fdt_generate_phandle
  7. fdt_mem_rsv
  8. fdt_get_mem_rsv
  9. fdt_num_mem_rsv
  10. nextprop_
  11. fdt_subnode_offset_namelen
  12. fdt_subnode_offset
  13. fdt_path_offset_namelen
  14. fdt_path_offset
  15. fdt_get_name
  16. fdt_first_property_offset
  17. fdt_next_property_offset
  18. fdt_get_property_by_offset_
  19. fdt_get_property_by_offset
  20. fdt_get_property_namelen_
  21. fdt_get_property_namelen
  22. fdt_get_property
  23. fdt_getprop_namelen
  24. fdt_getprop_by_offset
  25. fdt_getprop
  26. fdt_get_phandle
  27. fdt_get_alias_namelen
  28. fdt_get_alias
  29. fdt_get_path
  30. fdt_supernode_atdepth_offset
  31. fdt_node_depth
  32. fdt_parent_offset
  33. fdt_node_offset_by_prop_value
  34. fdt_node_offset_by_phandle
  35. fdt_stringlist_contains
  36. fdt_stringlist_count
  37. fdt_stringlist_search
  38. fdt_stringlist_get
  39. fdt_node_check_compatible
  40. fdt_node_offset_by_compatible
  41. fdt_check_full

   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 static int fdt_nodename_eq_(const void *fdt, int offset,
  14                             const char *s, int len)
  15 {
  16         int olen;
  17         const char *p = fdt_get_name(fdt, offset, &olen);
  18 
  19         if (!p || olen < len)
  20                 /* short match */
  21                 return 0;
  22 
  23         if (memcmp(p, s, len) != 0)
  24                 return 0;
  25 
  26         if (p[len] == '\0')
  27                 return 1;
  28         else if (!memchr(s, '@', len) && (p[len] == '@'))
  29                 return 1;
  30         else
  31                 return 0;
  32 }
  33 
  34 const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
  35 {
  36         uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
  37         size_t len;
  38         int err;
  39         const char *s, *n;
  40 
  41         err = fdt_ro_probe_(fdt);
  42         if (err != 0)
  43                 goto fail;
  44 
  45         err = -FDT_ERR_BADOFFSET;
  46         if (absoffset >= fdt_totalsize(fdt))
  47                 goto fail;
  48         len = fdt_totalsize(fdt) - absoffset;
  49 
  50         if (fdt_magic(fdt) == FDT_MAGIC) {
  51                 if (stroffset < 0)
  52                         goto fail;
  53                 if (fdt_version(fdt) >= 17) {
  54                         if (stroffset >= fdt_size_dt_strings(fdt))
  55                                 goto fail;
  56                         if ((fdt_size_dt_strings(fdt) - stroffset) < len)
  57                                 len = fdt_size_dt_strings(fdt) - stroffset;
  58                 }
  59         } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
  60                 if ((stroffset >= 0)
  61                     || (stroffset < -fdt_size_dt_strings(fdt)))
  62                         goto fail;
  63                 if ((-stroffset) < len)
  64                         len = -stroffset;
  65         } else {
  66                 err = -FDT_ERR_INTERNAL;
  67                 goto fail;
  68         }
  69 
  70         s = (const char *)fdt + absoffset;
  71         n = memchr(s, '\0', len);
  72         if (!n) {
  73                 /* missing terminating NULL */
  74                 err = -FDT_ERR_TRUNCATED;
  75                 goto fail;
  76         }
  77 
  78         if (lenp)
  79                 *lenp = n - s;
  80         return s;
  81 
  82 fail:
  83         if (lenp)
  84                 *lenp = err;
  85         return NULL;
  86 }
  87 
  88 const char *fdt_string(const void *fdt, int stroffset)
  89 {
  90         return fdt_get_string(fdt, stroffset, NULL);
  91 }
  92 
  93 static int fdt_string_eq_(const void *fdt, int stroffset,
  94                           const char *s, int len)
  95 {
  96         int slen;
  97         const char *p = fdt_get_string(fdt, stroffset, &slen);
  98 
  99         return p && (slen == len) && (memcmp(p, s, len) == 0);
 100 }
 101 
 102 int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
 103 {
 104         uint32_t max = 0;
 105         int offset = -1;
 106 
 107         while (true) {
 108                 uint32_t value;
 109 
 110                 offset = fdt_next_node(fdt, offset, NULL);
 111                 if (offset < 0) {
 112                         if (offset == -FDT_ERR_NOTFOUND)
 113                                 break;
 114 
 115                         return offset;
 116                 }
 117 
 118                 value = fdt_get_phandle(fdt, offset);
 119 
 120                 if (value > max)
 121                         max = value;
 122         }
 123 
 124         if (phandle)
 125                 *phandle = max;
 126 
 127         return 0;
 128 }
 129 
 130 int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
 131 {
 132         uint32_t max;
 133         int err;
 134 
 135         err = fdt_find_max_phandle(fdt, &max);
 136         if (err < 0)
 137                 return err;
 138 
 139         if (max == FDT_MAX_PHANDLE)
 140                 return -FDT_ERR_NOPHANDLES;
 141 
 142         if (phandle)
 143                 *phandle = max + 1;
 144 
 145         return 0;
 146 }
 147 
 148 static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
 149 {
 150         int offset = n * sizeof(struct fdt_reserve_entry);
 151         int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
 152 
 153         if (absoffset < fdt_off_mem_rsvmap(fdt))
 154                 return NULL;
 155         if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
 156                 return NULL;
 157         return fdt_mem_rsv_(fdt, n);
 158 }
 159 
 160 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
 161 {
 162         const struct fdt_reserve_entry *re;
 163 
 164         FDT_RO_PROBE(fdt);
 165         re = fdt_mem_rsv(fdt, n);
 166         if (!re)
 167                 return -FDT_ERR_BADOFFSET;
 168 
 169         *address = fdt64_ld(&re->address);
 170         *size = fdt64_ld(&re->size);
 171         return 0;
 172 }
 173 
 174 int fdt_num_mem_rsv(const void *fdt)
 175 {
 176         int i;
 177         const struct fdt_reserve_entry *re;
 178 
 179         for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
 180                 if (fdt64_ld(&re->size) == 0)
 181                         return i;
 182         }
 183         return -FDT_ERR_TRUNCATED;
 184 }
 185 
 186 static int nextprop_(const void *fdt, int offset)
 187 {
 188         uint32_t tag;
 189         int nextoffset;
 190 
 191         do {
 192                 tag = fdt_next_tag(fdt, offset, &nextoffset);
 193 
 194                 switch (tag) {
 195                 case FDT_END:
 196                         if (nextoffset >= 0)
 197                                 return -FDT_ERR_BADSTRUCTURE;
 198                         else
 199                                 return nextoffset;
 200 
 201                 case FDT_PROP:
 202                         return offset;
 203                 }
 204                 offset = nextoffset;
 205         } while (tag == FDT_NOP);
 206 
 207         return -FDT_ERR_NOTFOUND;
 208 }
 209 
 210 int fdt_subnode_offset_namelen(const void *fdt, int offset,
 211                                const char *name, int namelen)
 212 {
 213         int depth;
 214 
 215         FDT_RO_PROBE(fdt);
 216 
 217         for (depth = 0;
 218              (offset >= 0) && (depth >= 0);
 219              offset = fdt_next_node(fdt, offset, &depth))
 220                 if ((depth == 1)
 221                     && fdt_nodename_eq_(fdt, offset, name, namelen))
 222                         return offset;
 223 
 224         if (depth < 0)
 225                 return -FDT_ERR_NOTFOUND;
 226         return offset; /* error */
 227 }
 228 
 229 int fdt_subnode_offset(const void *fdt, int parentoffset,
 230                        const char *name)
 231 {
 232         return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
 233 }
 234 
 235 int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
 236 {
 237         const char *end = path + namelen;
 238         const char *p = path;
 239         int offset = 0;
 240 
 241         FDT_RO_PROBE(fdt);
 242 
 243         /* see if we have an alias */
 244         if (*path != '/') {
 245                 const char *q = memchr(path, '/', end - p);
 246 
 247                 if (!q)
 248                         q = end;
 249 
 250                 p = fdt_get_alias_namelen(fdt, p, q - p);
 251                 if (!p)
 252                         return -FDT_ERR_BADPATH;
 253                 offset = fdt_path_offset(fdt, p);
 254 
 255                 p = q;
 256         }
 257 
 258         while (p < end) {
 259                 const char *q;
 260 
 261                 while (*p == '/') {
 262                         p++;
 263                         if (p == end)
 264                                 return offset;
 265                 }
 266                 q = memchr(p, '/', end - p);
 267                 if (! q)
 268                         q = end;
 269 
 270                 offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
 271                 if (offset < 0)
 272                         return offset;
 273 
 274                 p = q;
 275         }
 276 
 277         return offset;
 278 }
 279 
 280 int fdt_path_offset(const void *fdt, const char *path)
 281 {
 282         return fdt_path_offset_namelen(fdt, path, strlen(path));
 283 }
 284 
 285 const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
 286 {
 287         const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
 288         const char *nameptr;
 289         int err;
 290 
 291         if (((err = fdt_ro_probe_(fdt)) != 0)
 292             || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
 293                         goto fail;
 294 
 295         nameptr = nh->name;
 296 
 297         if (fdt_version(fdt) < 0x10) {
 298                 /*
 299                  * For old FDT versions, match the naming conventions of V16:
 300                  * give only the leaf name (after all /). The actual tree
 301                  * contents are loosely checked.
 302                  */
 303                 const char *leaf;
 304                 leaf = strrchr(nameptr, '/');
 305                 if (leaf == NULL) {
 306                         err = -FDT_ERR_BADSTRUCTURE;
 307                         goto fail;
 308                 }
 309                 nameptr = leaf+1;
 310         }
 311 
 312         if (len)
 313                 *len = strlen(nameptr);
 314 
 315         return nameptr;
 316 
 317  fail:
 318         if (len)
 319                 *len = err;
 320         return NULL;
 321 }
 322 
 323 int fdt_first_property_offset(const void *fdt, int nodeoffset)
 324 {
 325         int offset;
 326 
 327         if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
 328                 return offset;
 329 
 330         return nextprop_(fdt, offset);
 331 }
 332 
 333 int fdt_next_property_offset(const void *fdt, int offset)
 334 {
 335         if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
 336                 return offset;
 337 
 338         return nextprop_(fdt, offset);
 339 }
 340 
 341 static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
 342                                                               int offset,
 343                                                               int *lenp)
 344 {
 345         int err;
 346         const struct fdt_property *prop;
 347 
 348         if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
 349                 if (lenp)
 350                         *lenp = err;
 351                 return NULL;
 352         }
 353 
 354         prop = fdt_offset_ptr_(fdt, offset);
 355 
 356         if (lenp)
 357                 *lenp = fdt32_ld(&prop->len);
 358 
 359         return prop;
 360 }
 361 
 362 const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
 363                                                       int offset,
 364                                                       int *lenp)
 365 {
 366         /* Prior to version 16, properties may need realignment
 367          * and this API does not work. fdt_getprop_*() will, however. */
 368 
 369         if (fdt_version(fdt) < 0x10) {
 370                 if (lenp)
 371                         *lenp = -FDT_ERR_BADVERSION;
 372                 return NULL;
 373         }
 374 
 375         return fdt_get_property_by_offset_(fdt, offset, lenp);
 376 }
 377 
 378 static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
 379                                                             int offset,
 380                                                             const char *name,
 381                                                             int namelen,
 382                                                             int *lenp,
 383                                                             int *poffset)
 384 {
 385         for (offset = fdt_first_property_offset(fdt, offset);
 386              (offset >= 0);
 387              (offset = fdt_next_property_offset(fdt, offset))) {
 388                 const struct fdt_property *prop;
 389 
 390                 if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
 391                         offset = -FDT_ERR_INTERNAL;
 392                         break;
 393                 }
 394                 if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
 395                                    name, namelen)) {
 396                         if (poffset)
 397                                 *poffset = offset;
 398                         return prop;
 399                 }
 400         }
 401 
 402         if (lenp)
 403                 *lenp = offset;
 404         return NULL;
 405 }
 406 
 407 
 408 const struct fdt_property *fdt_get_property_namelen(const void *fdt,
 409                                                     int offset,
 410                                                     const char *name,
 411                                                     int namelen, int *lenp)
 412 {
 413         /* Prior to version 16, properties may need realignment
 414          * and this API does not work. fdt_getprop_*() will, however. */
 415         if (fdt_version(fdt) < 0x10) {
 416                 if (lenp)
 417                         *lenp = -FDT_ERR_BADVERSION;
 418                 return NULL;
 419         }
 420 
 421         return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
 422                                          NULL);
 423 }
 424 
 425 
 426 const struct fdt_property *fdt_get_property(const void *fdt,
 427                                             int nodeoffset,
 428                                             const char *name, int *lenp)
 429 {
 430         return fdt_get_property_namelen(fdt, nodeoffset, name,
 431                                         strlen(name), lenp);
 432 }
 433 
 434 const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
 435                                 const char *name, int namelen, int *lenp)
 436 {
 437         int poffset;
 438         const struct fdt_property *prop;
 439 
 440         prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
 441                                          &poffset);
 442         if (!prop)
 443                 return NULL;
 444 
 445         /* Handle realignment */
 446         if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
 447             fdt32_ld(&prop->len) >= 8)
 448                 return prop->data + 4;
 449         return prop->data;
 450 }
 451 
 452 const void *fdt_getprop_by_offset(const void *fdt, int offset,
 453                                   const char **namep, int *lenp)
 454 {
 455         const struct fdt_property *prop;
 456 
 457         prop = fdt_get_property_by_offset_(fdt, offset, lenp);
 458         if (!prop)
 459                 return NULL;
 460         if (namep) {
 461                 const char *name;
 462                 int namelen;
 463                 name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
 464                                       &namelen);
 465                 if (!name) {
 466                         if (lenp)
 467                                 *lenp = namelen;
 468                         return NULL;
 469                 }
 470                 *namep = name;
 471         }
 472 
 473         /* Handle realignment */
 474         if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
 475             fdt32_ld(&prop->len) >= 8)
 476                 return prop->data + 4;
 477         return prop->data;
 478 }
 479 
 480 const void *fdt_getprop(const void *fdt, int nodeoffset,
 481                         const char *name, int *lenp)
 482 {
 483         return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
 484 }
 485 
 486 uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
 487 {
 488         const fdt32_t *php;
 489         int len;
 490 
 491         /* FIXME: This is a bit sub-optimal, since we potentially scan
 492          * over all the properties twice. */
 493         php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
 494         if (!php || (len != sizeof(*php))) {
 495                 php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
 496                 if (!php || (len != sizeof(*php)))
 497                         return 0;
 498         }
 499 
 500         return fdt32_ld(php);
 501 }
 502 
 503 const char *fdt_get_alias_namelen(const void *fdt,
 504                                   const char *name, int namelen)
 505 {
 506         int aliasoffset;
 507 
 508         aliasoffset = fdt_path_offset(fdt, "/aliases");
 509         if (aliasoffset < 0)
 510                 return NULL;
 511 
 512         return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
 513 }
 514 
 515 const char *fdt_get_alias(const void *fdt, const char *name)
 516 {
 517         return fdt_get_alias_namelen(fdt, name, strlen(name));
 518 }
 519 
 520 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
 521 {
 522         int pdepth = 0, p = 0;
 523         int offset, depth, namelen;
 524         const char *name;
 525 
 526         FDT_RO_PROBE(fdt);
 527 
 528         if (buflen < 2)
 529                 return -FDT_ERR_NOSPACE;
 530 
 531         for (offset = 0, depth = 0;
 532              (offset >= 0) && (offset <= nodeoffset);
 533              offset = fdt_next_node(fdt, offset, &depth)) {
 534                 while (pdepth > depth) {
 535                         do {
 536                                 p--;
 537                         } while (buf[p-1] != '/');
 538                         pdepth--;
 539                 }
 540 
 541                 if (pdepth >= depth) {
 542                         name = fdt_get_name(fdt, offset, &namelen);
 543                         if (!name)
 544                                 return namelen;
 545                         if ((p + namelen + 1) <= buflen) {
 546                                 memcpy(buf + p, name, namelen);
 547                                 p += namelen;
 548                                 buf[p++] = '/';
 549                                 pdepth++;
 550                         }
 551                 }
 552 
 553                 if (offset == nodeoffset) {
 554                         if (pdepth < (depth + 1))
 555                                 return -FDT_ERR_NOSPACE;
 556 
 557                         if (p > 1) /* special case so that root path is "/", not "" */
 558                                 p--;
 559                         buf[p] = '\0';
 560                         return 0;
 561                 }
 562         }
 563 
 564         if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
 565                 return -FDT_ERR_BADOFFSET;
 566         else if (offset == -FDT_ERR_BADOFFSET)
 567                 return -FDT_ERR_BADSTRUCTURE;
 568 
 569         return offset; /* error from fdt_next_node() */
 570 }
 571 
 572 int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
 573                                  int supernodedepth, int *nodedepth)
 574 {
 575         int offset, depth;
 576         int supernodeoffset = -FDT_ERR_INTERNAL;
 577 
 578         FDT_RO_PROBE(fdt);
 579 
 580         if (supernodedepth < 0)
 581                 return -FDT_ERR_NOTFOUND;
 582 
 583         for (offset = 0, depth = 0;
 584              (offset >= 0) && (offset <= nodeoffset);
 585              offset = fdt_next_node(fdt, offset, &depth)) {
 586                 if (depth == supernodedepth)
 587                         supernodeoffset = offset;
 588 
 589                 if (offset == nodeoffset) {
 590                         if (nodedepth)
 591                                 *nodedepth = depth;
 592 
 593                         if (supernodedepth > depth)
 594                                 return -FDT_ERR_NOTFOUND;
 595                         else
 596                                 return supernodeoffset;
 597                 }
 598         }
 599 
 600         if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
 601                 return -FDT_ERR_BADOFFSET;
 602         else if (offset == -FDT_ERR_BADOFFSET)
 603                 return -FDT_ERR_BADSTRUCTURE;
 604 
 605         return offset; /* error from fdt_next_node() */
 606 }
 607 
 608 int fdt_node_depth(const void *fdt, int nodeoffset)
 609 {
 610         int nodedepth;
 611         int err;
 612 
 613         err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
 614         if (err)
 615                 return (err < 0) ? err : -FDT_ERR_INTERNAL;
 616         return nodedepth;
 617 }
 618 
 619 int fdt_parent_offset(const void *fdt, int nodeoffset)
 620 {
 621         int nodedepth = fdt_node_depth(fdt, nodeoffset);
 622 
 623         if (nodedepth < 0)
 624                 return nodedepth;
 625         return fdt_supernode_atdepth_offset(fdt, nodeoffset,
 626                                             nodedepth - 1, NULL);
 627 }
 628 
 629 int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
 630                                   const char *propname,
 631                                   const void *propval, int proplen)
 632 {
 633         int offset;
 634         const void *val;
 635         int len;
 636 
 637         FDT_RO_PROBE(fdt);
 638 
 639         /* FIXME: The algorithm here is pretty horrible: we scan each
 640          * property of a node in fdt_getprop(), then if that didn't
 641          * find what we want, we scan over them again making our way
 642          * to the next node.  Still it's the easiest to implement
 643          * approach; performance can come later. */
 644         for (offset = fdt_next_node(fdt, startoffset, NULL);
 645              offset >= 0;
 646              offset = fdt_next_node(fdt, offset, NULL)) {
 647                 val = fdt_getprop(fdt, offset, propname, &len);
 648                 if (val && (len == proplen)
 649                     && (memcmp(val, propval, len) == 0))
 650                         return offset;
 651         }
 652 
 653         return offset; /* error from fdt_next_node() */
 654 }
 655 
 656 int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
 657 {
 658         int offset;
 659 
 660         if ((phandle == 0) || (phandle == -1))
 661                 return -FDT_ERR_BADPHANDLE;
 662 
 663         FDT_RO_PROBE(fdt);
 664 
 665         /* FIXME: The algorithm here is pretty horrible: we
 666          * potentially scan each property of a node in
 667          * fdt_get_phandle(), then if that didn't find what
 668          * we want, we scan over them again making our way to the next
 669          * node.  Still it's the easiest to implement approach;
 670          * performance can come later. */
 671         for (offset = fdt_next_node(fdt, -1, NULL);
 672              offset >= 0;
 673              offset = fdt_next_node(fdt, offset, NULL)) {
 674                 if (fdt_get_phandle(fdt, offset) == phandle)
 675                         return offset;
 676         }
 677 
 678         return offset; /* error from fdt_next_node() */
 679 }
 680 
 681 int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
 682 {
 683         int len = strlen(str);
 684         const char *p;
 685 
 686         while (listlen >= len) {
 687                 if (memcmp(str, strlist, len+1) == 0)
 688                         return 1;
 689                 p = memchr(strlist, '\0', listlen);
 690                 if (!p)
 691                         return 0; /* malformed strlist.. */
 692                 listlen -= (p-strlist) + 1;
 693                 strlist = p + 1;
 694         }
 695         return 0;
 696 }
 697 
 698 int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
 699 {
 700         const char *list, *end;
 701         int length, count = 0;
 702 
 703         list = fdt_getprop(fdt, nodeoffset, property, &length);
 704         if (!list)
 705                 return length;
 706 
 707         end = list + length;
 708 
 709         while (list < end) {
 710                 length = strnlen(list, end - list) + 1;
 711 
 712                 /* Abort if the last string isn't properly NUL-terminated. */
 713                 if (list + length > end)
 714                         return -FDT_ERR_BADVALUE;
 715 
 716                 list += length;
 717                 count++;
 718         }
 719 
 720         return count;
 721 }
 722 
 723 int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
 724                           const char *string)
 725 {
 726         int length, len, idx = 0;
 727         const char *list, *end;
 728 
 729         list = fdt_getprop(fdt, nodeoffset, property, &length);
 730         if (!list)
 731                 return length;
 732 
 733         len = strlen(string) + 1;
 734         end = list + length;
 735 
 736         while (list < end) {
 737                 length = strnlen(list, end - list) + 1;
 738 
 739                 /* Abort if the last string isn't properly NUL-terminated. */
 740                 if (list + length > end)
 741                         return -FDT_ERR_BADVALUE;
 742 
 743                 if (length == len && memcmp(list, string, length) == 0)
 744                         return idx;
 745 
 746                 list += length;
 747                 idx++;
 748         }
 749 
 750         return -FDT_ERR_NOTFOUND;
 751 }
 752 
 753 const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
 754                                const char *property, int idx,
 755                                int *lenp)
 756 {
 757         const char *list, *end;
 758         int length;
 759 
 760         list = fdt_getprop(fdt, nodeoffset, property, &length);
 761         if (!list) {
 762                 if (lenp)
 763                         *lenp = length;
 764 
 765                 return NULL;
 766         }
 767 
 768         end = list + length;
 769 
 770         while (list < end) {
 771                 length = strnlen(list, end - list) + 1;
 772 
 773                 /* Abort if the last string isn't properly NUL-terminated. */
 774                 if (list + length > end) {
 775                         if (lenp)
 776                                 *lenp = -FDT_ERR_BADVALUE;
 777 
 778                         return NULL;
 779                 }
 780 
 781                 if (idx == 0) {
 782                         if (lenp)
 783                                 *lenp = length - 1;
 784 
 785                         return list;
 786                 }
 787 
 788                 list += length;
 789                 idx--;
 790         }
 791 
 792         if (lenp)
 793                 *lenp = -FDT_ERR_NOTFOUND;
 794 
 795         return NULL;
 796 }
 797 
 798 int fdt_node_check_compatible(const void *fdt, int nodeoffset,
 799                               const char *compatible)
 800 {
 801         const void *prop;
 802         int len;
 803 
 804         prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
 805         if (!prop)
 806                 return len;
 807 
 808         return !fdt_stringlist_contains(prop, len, compatible);
 809 }
 810 
 811 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
 812                                   const char *compatible)
 813 {
 814         int offset, err;
 815 
 816         FDT_RO_PROBE(fdt);
 817 
 818         /* FIXME: The algorithm here is pretty horrible: we scan each
 819          * property of a node in fdt_node_check_compatible(), then if
 820          * that didn't find what we want, we scan over them again
 821          * making our way to the next node.  Still it's the easiest to
 822          * implement approach; performance can come later. */
 823         for (offset = fdt_next_node(fdt, startoffset, NULL);
 824              offset >= 0;
 825              offset = fdt_next_node(fdt, offset, NULL)) {
 826                 err = fdt_node_check_compatible(fdt, offset, compatible);
 827                 if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
 828                         return err;
 829                 else if (err == 0)
 830                         return offset;
 831         }
 832 
 833         return offset; /* error from fdt_next_node() */
 834 }
 835 
 836 int fdt_check_full(const void *fdt, size_t bufsize)
 837 {
 838         int err;
 839         int num_memrsv;
 840         int offset, nextoffset = 0;
 841         uint32_t tag;
 842         unsigned depth = 0;
 843         const void *prop;
 844         const char *propname;
 845 
 846         if (bufsize < FDT_V1_SIZE)
 847                 return -FDT_ERR_TRUNCATED;
 848         err = fdt_check_header(fdt);
 849         if (err != 0)
 850                 return err;
 851         if (bufsize < fdt_totalsize(fdt))
 852                 return -FDT_ERR_TRUNCATED;
 853 
 854         num_memrsv = fdt_num_mem_rsv(fdt);
 855         if (num_memrsv < 0)
 856                 return num_memrsv;
 857 
 858         while (1) {
 859                 offset = nextoffset;
 860                 tag = fdt_next_tag(fdt, offset, &nextoffset);
 861 
 862                 if (nextoffset < 0)
 863                         return nextoffset;
 864 
 865                 switch (tag) {
 866                 case FDT_NOP:
 867                         break;
 868 
 869                 case FDT_END:
 870                         if (depth != 0)
 871                                 return -FDT_ERR_BADSTRUCTURE;
 872                         return 0;
 873 
 874                 case FDT_BEGIN_NODE:
 875                         depth++;
 876                         if (depth > INT_MAX)
 877                                 return -FDT_ERR_BADSTRUCTURE;
 878                         break;
 879 
 880                 case FDT_END_NODE:
 881                         if (depth == 0)
 882                                 return -FDT_ERR_BADSTRUCTURE;
 883                         depth--;
 884                         break;
 885 
 886                 case FDT_PROP:
 887                         prop = fdt_getprop_by_offset(fdt, offset, &propname,
 888                                                      &err);
 889                         if (!prop)
 890                                 return err;
 891                         break;
 892 
 893                 default:
 894                         return -FDT_ERR_INTERNAL;
 895                 }
 896         }
 897 }

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