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