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