1 /* 2 * (C) Copyright 2007 3 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com 4 * Based on code written by: 5 * Pantelis Antoniou <pantelis.antoniou@gmail.com> and 6 * Matthew McClintock <msm@freescale.com> 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <command.h> 13 #include <linux/ctype.h> 14 #include <linux/types.h> 15 #include <asm/global_data.h> 16 #include <linux/libfdt.h> 17 #include <fdt_support.h> 18 #include <mapmem.h> 19 #include <asm/io.h> 20 21 #define MAX_LEVEL 32 /* how deeply nested we will go */ 22 #define SCRATCHPAD 1024 /* bytes of scratchpad memory */ 23 #define CMD_FDT_MAX_DUMP 64 24 25 /* 26 * Global data (for the gd->bd) 27 */ 28 DECLARE_GLOBAL_DATA_PTR; 29 30 static int fdt_valid(struct fdt_header **blobp); 31 static int fdt_parse_prop(char *const*newval, int count, char *data, int *len); 32 static int fdt_print(const char *pathp, char *prop, int depth); 33 static int is_printable_string(const void *data, int len); 34 35 /* 36 * The working_fdt points to our working flattened device tree. 37 */ 38 struct fdt_header *working_fdt; 39 40 void set_working_fdt_addr(ulong addr) 41 { 42 void *buf; 43 44 buf = map_sysmem(addr, 0); 45 working_fdt = buf; 46 env_set_hex("fdtaddr", addr); 47 } 48 49 /* 50 * Get a value from the fdt and format it to be set in the environment 51 */ 52 static int fdt_value_env_set(const void *nodep, int len, const char *var) 53 { 54 if (is_printable_string(nodep, len)) 55 env_set(var, (void *)nodep); 56 else if (len == 4) { 57 char buf[11]; 58 59 sprintf(buf, "0x%08X", fdt32_to_cpu(*(fdt32_t *)nodep)); 60 env_set(var, buf); 61 } else if (len%4 == 0 && len <= 20) { 62 /* Needed to print things like sha1 hashes. */ 63 char buf[41]; 64 int i; 65 66 for (i = 0; i < len; i += sizeof(unsigned int)) 67 sprintf(buf + (i * 2), "%08x", 68 *(unsigned int *)(nodep + i)); 69 env_set(var, buf); 70 } else { 71 printf("error: unprintable value\n"); 72 return 1; 73 } 74 return 0; 75 } 76 77 /* 78 * Flattened Device Tree command, see the help for parameter definitions. 79 */ 80 static int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 81 { 82 if (argc < 2) 83 return CMD_RET_USAGE; 84 85 /* 86 * Set the address of the fdt 87 */ 88 if (strncmp(argv[1], "ad", 2) == 0) { 89 unsigned long addr; 90 int control = 0; 91 struct fdt_header *blob; 92 /* 93 * Set the address [and length] of the fdt. 94 */ 95 argc -= 2; 96 argv += 2; 97 /* Temporary #ifdef - some archs don't have fdt_blob yet */ 98 #ifdef CONFIG_OF_CONTROL 99 if (argc && !strcmp(*argv, "-c")) { 100 control = 1; 101 argc--; 102 argv++; 103 } 104 #endif 105 if (argc == 0) { 106 if (control) 107 blob = (struct fdt_header *)gd->fdt_blob; 108 else 109 blob = working_fdt; 110 if (!blob || !fdt_valid(&blob)) 111 return 1; 112 printf("The address of the fdt is %#08lx\n", 113 control ? (ulong)map_to_sysmem(blob) : 114 env_get_hex("fdtaddr", 0)); 115 return 0; 116 } 117 118 addr = simple_strtoul(argv[0], NULL, 16); 119 blob = map_sysmem(addr, 0); 120 if (!fdt_valid(&blob)) 121 return 1; 122 if (control) 123 gd->fdt_blob = blob; 124 else 125 set_working_fdt_addr(addr); 126 127 if (argc >= 2) { 128 int len; 129 int err; 130 /* 131 * Optional new length 132 */ 133 len = simple_strtoul(argv[1], NULL, 16); 134 if (len < fdt_totalsize(blob)) { 135 printf ("New length %d < existing length %d, " 136 "ignoring.\n", 137 len, fdt_totalsize(blob)); 138 } else { 139 /* 140 * Open in place with a new length. 141 */ 142 err = fdt_open_into(blob, blob, len); 143 if (err != 0) { 144 printf ("libfdt fdt_open_into(): %s\n", 145 fdt_strerror(err)); 146 } 147 } 148 } 149 150 return CMD_RET_SUCCESS; 151 } 152 153 if (!working_fdt) { 154 working_fdt = (void *)gd->fdt_blob; 155 printf("No FDT memory address configured. Default at 0x%08lx\n", 156 (ulong)gd->fdt_blob); 157 } 158 159 /* 160 * Move the working_fdt 161 */ 162 if (strncmp(argv[1], "mo", 2) == 0) { 163 struct fdt_header *newaddr; 164 int len; 165 int err; 166 167 if (argc < 4) 168 return CMD_RET_USAGE; 169 170 /* 171 * Set the address and length of the fdt. 172 */ 173 working_fdt = (struct fdt_header *)simple_strtoul(argv[2], NULL, 16); 174 if (!fdt_valid(&working_fdt)) 175 return 1; 176 177 newaddr = (struct fdt_header *)simple_strtoul(argv[3],NULL,16); 178 179 /* 180 * If the user specifies a length, use that. Otherwise use the 181 * current length. 182 */ 183 if (argc <= 4) { 184 len = fdt_totalsize(working_fdt); 185 } else { 186 len = simple_strtoul(argv[4], NULL, 16); 187 if (len < fdt_totalsize(working_fdt)) { 188 printf ("New length 0x%X < existing length " 189 "0x%X, aborting.\n", 190 len, fdt_totalsize(working_fdt)); 191 return 1; 192 } 193 } 194 195 /* 196 * Copy to the new location. 197 */ 198 err = fdt_open_into(working_fdt, newaddr, len); 199 if (err != 0) { 200 printf ("libfdt fdt_open_into(): %s\n", 201 fdt_strerror(err)); 202 return 1; 203 } 204 working_fdt = newaddr; 205 #ifdef CONFIG_OF_SYSTEM_SETUP 206 /* Call the board-specific fixup routine */ 207 } else if (strncmp(argv[1], "sys", 3) == 0) { 208 int err = ft_system_setup(working_fdt, gd->bd); 209 210 if (err) { 211 printf("Failed to add system information to FDT: %s\n", 212 fdt_strerror(err)); 213 return CMD_RET_FAILURE; 214 } 215 #endif 216 /* 217 * Make a new node 218 */ 219 } else if (strncmp(argv[1], "mk", 2) == 0) { 220 char *pathp; /* path */ 221 char *nodep; /* new node to add */ 222 int nodeoffset; /* node offset from libfdt */ 223 int err; 224 225 /* 226 * Parameters: Node path, new node to be appended to the path. 227 */ 228 if (argc < 4) 229 return CMD_RET_USAGE; 230 231 pathp = argv[2]; 232 nodep = argv[3]; 233 234 nodeoffset = fdt_path_offset (working_fdt, pathp); 235 if (nodeoffset < 0) { 236 /* 237 * Not found or something else bad happened. 238 */ 239 printf ("libfdt fdt_path_offset() returned %s\n", 240 fdt_strerror(nodeoffset)); 241 return 1; 242 } 243 err = fdt_add_subnode(working_fdt, nodeoffset, nodep); 244 if (err < 0) { 245 printf ("libfdt fdt_add_subnode(): %s\n", 246 fdt_strerror(err)); 247 return 1; 248 } 249 250 /* 251 * Set the value of a property in the working_fdt. 252 */ 253 } else if (argv[1][0] == 's') { 254 char *pathp; /* path */ 255 char *prop; /* property */ 256 int nodeoffset; /* node offset from libfdt */ 257 static char data[SCRATCHPAD] __aligned(4);/* property storage */ 258 const void *ptmp; 259 int len; /* new length of the property */ 260 int ret; /* return value */ 261 262 /* 263 * Parameters: Node path, property, optional value. 264 */ 265 if (argc < 4) 266 return CMD_RET_USAGE; 267 268 pathp = argv[2]; 269 prop = argv[3]; 270 271 nodeoffset = fdt_path_offset (working_fdt, pathp); 272 if (nodeoffset < 0) { 273 /* 274 * Not found or something else bad happened. 275 */ 276 printf ("libfdt fdt_path_offset() returned %s\n", 277 fdt_strerror(nodeoffset)); 278 return 1; 279 } 280 281 if (argc == 4) { 282 len = 0; 283 } else { 284 ptmp = fdt_getprop(working_fdt, nodeoffset, prop, &len); 285 if (len > SCRATCHPAD) { 286 printf("prop (%d) doesn't fit in scratchpad!\n", 287 len); 288 return 1; 289 } 290 if (ptmp != NULL) 291 memcpy(data, ptmp, len); 292 293 ret = fdt_parse_prop(&argv[4], argc - 4, data, &len); 294 if (ret != 0) 295 return ret; 296 } 297 298 ret = fdt_setprop(working_fdt, nodeoffset, prop, data, len); 299 if (ret < 0) { 300 printf ("libfdt fdt_setprop(): %s\n", fdt_strerror(ret)); 301 return 1; 302 } 303 304 /******************************************************************** 305 * Get the value of a property in the working_fdt. 306 ********************************************************************/ 307 } else if (argv[1][0] == 'g') { 308 char *subcmd; /* sub-command */ 309 char *pathp; /* path */ 310 char *prop; /* property */ 311 char *var; /* variable to store result */ 312 int nodeoffset; /* node offset from libfdt */ 313 const void *nodep; /* property node pointer */ 314 int len = 0; /* new length of the property */ 315 316 /* 317 * Parameters: Node path, property, optional value. 318 */ 319 if (argc < 5) 320 return CMD_RET_USAGE; 321 322 subcmd = argv[2]; 323 324 if (argc < 6 && subcmd[0] != 's') 325 return CMD_RET_USAGE; 326 327 var = argv[3]; 328 pathp = argv[4]; 329 prop = argv[5]; 330 331 nodeoffset = fdt_path_offset(working_fdt, pathp); 332 if (nodeoffset < 0) { 333 /* 334 * Not found or something else bad happened. 335 */ 336 printf("libfdt fdt_path_offset() returned %s\n", 337 fdt_strerror(nodeoffset)); 338 return 1; 339 } 340 341 if (subcmd[0] == 'n' || (subcmd[0] == 's' && argc == 5)) { 342 int reqIndex = -1; 343 int startDepth = fdt_node_depth( 344 working_fdt, nodeoffset); 345 int curDepth = startDepth; 346 int curIndex = -1; 347 int nextNodeOffset = fdt_next_node( 348 working_fdt, nodeoffset, &curDepth); 349 350 if (subcmd[0] == 'n') 351 reqIndex = simple_strtoul(argv[5], NULL, 16); 352 353 while (curDepth > startDepth) { 354 if (curDepth == startDepth + 1) 355 curIndex++; 356 if (subcmd[0] == 'n' && curIndex == reqIndex) { 357 const char *node_name; 358 359 node_name = fdt_get_name(working_fdt, 360 nextNodeOffset, 361 NULL); 362 env_set(var, node_name); 363 return 0; 364 } 365 nextNodeOffset = fdt_next_node( 366 working_fdt, nextNodeOffset, &curDepth); 367 if (nextNodeOffset < 0) 368 break; 369 } 370 if (subcmd[0] == 's') { 371 /* get the num nodes at this level */ 372 env_set_ulong(var, curIndex + 1); 373 } else { 374 /* node index not found */ 375 printf("libfdt node not found\n"); 376 return 1; 377 } 378 } else { 379 nodep = fdt_getprop( 380 working_fdt, nodeoffset, prop, &len); 381 if (len == 0) { 382 /* no property value */ 383 env_set(var, ""); 384 return 0; 385 } else if (nodep && len > 0) { 386 if (subcmd[0] == 'v') { 387 int ret; 388 389 ret = fdt_value_env_set(nodep, len, 390 var); 391 if (ret != 0) 392 return ret; 393 } else if (subcmd[0] == 'a') { 394 /* Get address */ 395 char buf[11]; 396 397 sprintf(buf, "0x%p", nodep); 398 env_set(var, buf); 399 } else if (subcmd[0] == 's') { 400 /* Get size */ 401 char buf[11]; 402 403 sprintf(buf, "0x%08X", len); 404 env_set(var, buf); 405 } else 406 return CMD_RET_USAGE; 407 return 0; 408 } else { 409 printf("libfdt fdt_getprop(): %s\n", 410 fdt_strerror(len)); 411 return 1; 412 } 413 } 414 415 /* 416 * Print (recursive) / List (single level) 417 */ 418 } else if ((argv[1][0] == 'p') || (argv[1][0] == 'l')) { 419 int depth = MAX_LEVEL; /* how deep to print */ 420 char *pathp; /* path */ 421 char *prop; /* property */ 422 int ret; /* return value */ 423 static char root[2] = "/"; 424 425 /* 426 * list is an alias for print, but limited to 1 level 427 */ 428 if (argv[1][0] == 'l') { 429 depth = 1; 430 } 431 432 /* 433 * Get the starting path. The root node is an oddball, 434 * the offset is zero and has no name. 435 */ 436 if (argc == 2) 437 pathp = root; 438 else 439 pathp = argv[2]; 440 if (argc > 3) 441 prop = argv[3]; 442 else 443 prop = NULL; 444 445 ret = fdt_print(pathp, prop, depth); 446 if (ret != 0) 447 return ret; 448 449 /* 450 * Remove a property/node 451 */ 452 } else if (strncmp(argv[1], "rm", 2) == 0) { 453 int nodeoffset; /* node offset from libfdt */ 454 int err; 455 456 /* 457 * Get the path. The root node is an oddball, the offset 458 * is zero and has no name. 459 */ 460 nodeoffset = fdt_path_offset (working_fdt, argv[2]); 461 if (nodeoffset < 0) { 462 /* 463 * Not found or something else bad happened. 464 */ 465 printf ("libfdt fdt_path_offset() returned %s\n", 466 fdt_strerror(nodeoffset)); 467 return 1; 468 } 469 /* 470 * Do the delete. A fourth parameter means delete a property, 471 * otherwise delete the node. 472 */ 473 if (argc > 3) { 474 err = fdt_delprop(working_fdt, nodeoffset, argv[3]); 475 if (err < 0) { 476 printf("libfdt fdt_delprop(): %s\n", 477 fdt_strerror(err)); 478 return err; 479 } 480 } else { 481 err = fdt_del_node(working_fdt, nodeoffset); 482 if (err < 0) { 483 printf("libfdt fdt_del_node(): %s\n", 484 fdt_strerror(err)); 485 return err; 486 } 487 } 488 489 /* 490 * Display header info 491 */ 492 } else if (argv[1][0] == 'h') { 493 u32 version = fdt_version(working_fdt); 494 printf("magic:\t\t\t0x%x\n", fdt_magic(working_fdt)); 495 printf("totalsize:\t\t0x%x (%d)\n", fdt_totalsize(working_fdt), 496 fdt_totalsize(working_fdt)); 497 printf("off_dt_struct:\t\t0x%x\n", 498 fdt_off_dt_struct(working_fdt)); 499 printf("off_dt_strings:\t\t0x%x\n", 500 fdt_off_dt_strings(working_fdt)); 501 printf("off_mem_rsvmap:\t\t0x%x\n", 502 fdt_off_mem_rsvmap(working_fdt)); 503 printf("version:\t\t%d\n", version); 504 printf("last_comp_version:\t%d\n", 505 fdt_last_comp_version(working_fdt)); 506 if (version >= 2) 507 printf("boot_cpuid_phys:\t0x%x\n", 508 fdt_boot_cpuid_phys(working_fdt)); 509 if (version >= 3) 510 printf("size_dt_strings:\t0x%x\n", 511 fdt_size_dt_strings(working_fdt)); 512 if (version >= 17) 513 printf("size_dt_struct:\t\t0x%x\n", 514 fdt_size_dt_struct(working_fdt)); 515 printf("number mem_rsv:\t\t0x%x\n", 516 fdt_num_mem_rsv(working_fdt)); 517 printf("\n"); 518 519 /* 520 * Set boot cpu id 521 */ 522 } else if (strncmp(argv[1], "boo", 3) == 0) { 523 unsigned long tmp = simple_strtoul(argv[2], NULL, 16); 524 fdt_set_boot_cpuid_phys(working_fdt, tmp); 525 526 /* 527 * memory command 528 */ 529 } else if (strncmp(argv[1], "me", 2) == 0) { 530 uint64_t addr, size; 531 int err; 532 addr = simple_strtoull(argv[2], NULL, 16); 533 size = simple_strtoull(argv[3], NULL, 16); 534 err = fdt_fixup_memory(working_fdt, addr, size); 535 if (err < 0) 536 return err; 537 538 /* 539 * mem reserve commands 540 */ 541 } else if (strncmp(argv[1], "rs", 2) == 0) { 542 if (argv[2][0] == 'p') { 543 uint64_t addr, size; 544 int total = fdt_num_mem_rsv(working_fdt); 545 int j, err; 546 printf("index\t\t start\t\t size\n"); 547 printf("-------------------------------" 548 "-----------------\n"); 549 for (j = 0; j < total; j++) { 550 err = fdt_get_mem_rsv(working_fdt, j, &addr, &size); 551 if (err < 0) { 552 printf("libfdt fdt_get_mem_rsv(): %s\n", 553 fdt_strerror(err)); 554 return err; 555 } 556 printf(" %x\t%08x%08x\t%08x%08x\n", j, 557 (u32)(addr >> 32), 558 (u32)(addr & 0xffffffff), 559 (u32)(size >> 32), 560 (u32)(size & 0xffffffff)); 561 } 562 } else if (argv[2][0] == 'a') { 563 uint64_t addr, size; 564 int err; 565 addr = simple_strtoull(argv[3], NULL, 16); 566 size = simple_strtoull(argv[4], NULL, 16); 567 err = fdt_add_mem_rsv(working_fdt, addr, size); 568 569 if (err < 0) { 570 printf("libfdt fdt_add_mem_rsv(): %s\n", 571 fdt_strerror(err)); 572 return err; 573 } 574 } else if (argv[2][0] == 'd') { 575 unsigned long idx = simple_strtoul(argv[3], NULL, 16); 576 int err = fdt_del_mem_rsv(working_fdt, idx); 577 578 if (err < 0) { 579 printf("libfdt fdt_del_mem_rsv(): %s\n", 580 fdt_strerror(err)); 581 return err; 582 } 583 } else { 584 /* Unrecognized command */ 585 return CMD_RET_USAGE; 586 } 587 } 588 #ifdef CONFIG_OF_BOARD_SETUP 589 /* Call the board-specific fixup routine */ 590 else if (strncmp(argv[1], "boa", 3) == 0) { 591 int err = ft_board_setup(working_fdt, gd->bd); 592 593 if (err) { 594 printf("Failed to update board information in FDT: %s\n", 595 fdt_strerror(err)); 596 return CMD_RET_FAILURE; 597 } 598 } 599 #endif 600 /* Create a chosen node */ 601 else if (strncmp(argv[1], "cho", 3) == 0) { 602 unsigned long initrd_start = 0, initrd_end = 0; 603 604 if ((argc != 2) && (argc != 4)) 605 return CMD_RET_USAGE; 606 607 if (argc == 4) { 608 initrd_start = simple_strtoul(argv[2], NULL, 16); 609 initrd_end = simple_strtoul(argv[3], NULL, 16); 610 } 611 612 fdt_chosen(working_fdt); 613 fdt_initrd(working_fdt, initrd_start, initrd_end); 614 615 #if defined(CONFIG_FIT_SIGNATURE) 616 } else if (strncmp(argv[1], "che", 3) == 0) { 617 int cfg_noffset; 618 int ret; 619 unsigned long addr; 620 struct fdt_header *blob; 621 622 if (!working_fdt) 623 return CMD_RET_FAILURE; 624 625 if (argc > 2) { 626 addr = simple_strtoul(argv[2], NULL, 16); 627 blob = map_sysmem(addr, 0); 628 } else { 629 blob = (struct fdt_header *)gd->fdt_blob; 630 } 631 if (!fdt_valid(&blob)) 632 return 1; 633 634 gd->fdt_blob = blob; 635 cfg_noffset = fit_conf_get_node(working_fdt, NULL); 636 if (!cfg_noffset) { 637 printf("Could not find configuration node: %s\n", 638 fdt_strerror(cfg_noffset)); 639 return CMD_RET_FAILURE; 640 } 641 642 ret = fit_config_verify(working_fdt, cfg_noffset); 643 if (ret == 0) 644 return CMD_RET_SUCCESS; 645 else 646 return CMD_RET_FAILURE; 647 #endif 648 649 } 650 #ifdef CONFIG_OF_LIBFDT_OVERLAY 651 /* apply an overlay */ 652 else if (strncmp(argv[1], "ap", 2) == 0) { 653 unsigned long addr; 654 struct fdt_header *blob; 655 int ret; 656 657 if (argc != 3) 658 return CMD_RET_USAGE; 659 660 if (!working_fdt) 661 return CMD_RET_FAILURE; 662 663 addr = simple_strtoul(argv[2], NULL, 16); 664 blob = map_sysmem(addr, 0); 665 if (!fdt_valid(&blob)) 666 return CMD_RET_FAILURE; 667 668 /* apply method prints messages on error */ 669 ret = fdt_overlay_apply_verbose(working_fdt, blob); 670 if (ret) 671 return CMD_RET_FAILURE; 672 } 673 #endif 674 /* resize the fdt */ 675 else if (strncmp(argv[1], "re", 2) == 0) { 676 uint extrasize; 677 if (argc > 2) 678 extrasize = simple_strtoul(argv[2], NULL, 16); 679 else 680 extrasize = 0; 681 fdt_shrink_to_minimum(working_fdt, extrasize); 682 } 683 else { 684 /* Unrecognized command */ 685 return CMD_RET_USAGE; 686 } 687 688 return 0; 689 } 690 691 /****************************************************************************/ 692 693 /** 694 * fdt_valid() - Check if an FDT is valid. If not, change it to NULL 695 * 696 * @blobp: Pointer to FDT pointer 697 * @return 1 if OK, 0 if bad (in which case *blobp is set to NULL) 698 */ 699 static int fdt_valid(struct fdt_header **blobp) 700 { 701 const void *blob = *blobp; 702 int err; 703 704 if (blob == NULL) { 705 printf ("The address of the fdt is invalid (NULL).\n"); 706 return 0; 707 } 708 709 err = fdt_check_header(blob); 710 if (err == 0) 711 return 1; /* valid */ 712 713 if (err < 0) { 714 printf("libfdt fdt_check_header(): %s", fdt_strerror(err)); 715 /* 716 * Be more informative on bad version. 717 */ 718 if (err == -FDT_ERR_BADVERSION) { 719 if (fdt_version(blob) < 720 FDT_FIRST_SUPPORTED_VERSION) { 721 printf (" - too old, fdt %d < %d", 722 fdt_version(blob), 723 FDT_FIRST_SUPPORTED_VERSION); 724 } 725 if (fdt_last_comp_version(blob) > 726 FDT_LAST_SUPPORTED_VERSION) { 727 printf (" - too new, fdt %d > %d", 728 fdt_version(blob), 729 FDT_LAST_SUPPORTED_VERSION); 730 } 731 } 732 printf("\n"); 733 *blobp = NULL; 734 return 0; 735 } 736 return 1; 737 } 738 739 /****************************************************************************/ 740 741 /* 742 * Parse the user's input, partially heuristic. Valid formats: 743 * <0x00112233 4 05> - an array of cells. Numbers follow standard 744 * C conventions. 745 * [00 11 22 .. nn] - byte stream 746 * "string" - If the the value doesn't start with "<" or "[", it is 747 * treated as a string. Note that the quotes are 748 * stripped by the parser before we get the string. 749 * newval: An array of strings containing the new property as specified 750 * on the command line 751 * count: The number of strings in the array 752 * data: A bytestream to be placed in the property 753 * len: The length of the resulting bytestream 754 */ 755 static int fdt_parse_prop(char * const *newval, int count, char *data, int *len) 756 { 757 char *cp; /* temporary char pointer */ 758 char *newp; /* temporary newval char pointer */ 759 unsigned long tmp; /* holds converted values */ 760 int stridx = 0; 761 762 *len = 0; 763 newp = newval[0]; 764 765 /* An array of cells */ 766 if (*newp == '<') { 767 newp++; 768 while ((*newp != '>') && (stridx < count)) { 769 /* 770 * Keep searching until we find that last ">" 771 * That way users don't have to escape the spaces 772 */ 773 if (*newp == '\0') { 774 newp = newval[++stridx]; 775 continue; 776 } 777 778 cp = newp; 779 tmp = simple_strtoul(cp, &newp, 0); 780 if (*cp != '?') 781 *(fdt32_t *)data = cpu_to_fdt32(tmp); 782 else 783 newp++; 784 785 data += 4; 786 *len += 4; 787 788 /* If the ptr didn't advance, something went wrong */ 789 if ((newp - cp) <= 0) { 790 printf("Sorry, I could not convert \"%s\"\n", 791 cp); 792 return 1; 793 } 794 795 while (*newp == ' ') 796 newp++; 797 } 798 799 if (*newp != '>') { 800 printf("Unexpected character '%c'\n", *newp); 801 return 1; 802 } 803 } else if (*newp == '[') { 804 /* 805 * Byte stream. Convert the values. 806 */ 807 newp++; 808 while ((stridx < count) && (*newp != ']')) { 809 while (*newp == ' ') 810 newp++; 811 if (*newp == '\0') { 812 newp = newval[++stridx]; 813 continue; 814 } 815 if (!isxdigit(*newp)) 816 break; 817 tmp = simple_strtoul(newp, &newp, 16); 818 *data++ = tmp & 0xFF; 819 *len = *len + 1; 820 } 821 if (*newp != ']') { 822 printf("Unexpected character '%c'\n", *newp); 823 return 1; 824 } 825 } else { 826 /* 827 * Assume it is one or more strings. Copy it into our 828 * data area for convenience (including the 829 * terminating '\0's). 830 */ 831 while (stridx < count) { 832 size_t length = strlen(newp) + 1; 833 strcpy(data, newp); 834 data += length; 835 *len += length; 836 newp = newval[++stridx]; 837 } 838 } 839 return 0; 840 } 841 842 /****************************************************************************/ 843 844 /* 845 * Heuristic to guess if this is a string or concatenated strings. 846 */ 847 848 static int is_printable_string(const void *data, int len) 849 { 850 const char *s = data; 851 852 /* zero length is not */ 853 if (len == 0) 854 return 0; 855 856 /* must terminate with zero or '\n' */ 857 if (s[len - 1] != '\0' && s[len - 1] != '\n') 858 return 0; 859 860 /* printable or a null byte (concatenated strings) */ 861 while (((*s == '\0') || isprint(*s) || isspace(*s)) && (len > 0)) { 862 /* 863 * If we see a null, there are three possibilities: 864 * 1) If len == 1, it is the end of the string, printable 865 * 2) Next character also a null, not printable. 866 * 3) Next character not a null, continue to check. 867 */ 868 if (s[0] == '\0') { 869 if (len == 1) 870 return 1; 871 if (s[1] == '\0') 872 return 0; 873 } 874 s++; 875 len--; 876 } 877 878 /* Not the null termination, or not done yet: not printable */ 879 if (*s != '\0' || (len != 0)) 880 return 0; 881 882 return 1; 883 } 884 885 886 /* 887 * Print the property in the best format, a heuristic guess. Print as 888 * a string, concatenated strings, a byte, word, double word, or (if all 889 * else fails) it is printed as a stream of bytes. 890 */ 891 static void print_data(const void *data, int len) 892 { 893 int j; 894 895 /* no data, don't print */ 896 if (len == 0) 897 return; 898 899 /* 900 * It is a string, but it may have multiple strings (embedded '\0's). 901 */ 902 if (is_printable_string(data, len)) { 903 puts("\""); 904 j = 0; 905 while (j < len) { 906 if (j > 0) 907 puts("\", \""); 908 puts(data); 909 j += strlen(data) + 1; 910 data += strlen(data) + 1; 911 } 912 puts("\""); 913 return; 914 } 915 916 if ((len %4) == 0) { 917 if (len > CMD_FDT_MAX_DUMP) 918 printf("* 0x%p [0x%08x]", data, len); 919 else { 920 const __be32 *p; 921 922 printf("<"); 923 for (j = 0, p = data; j < len/4; j++) 924 printf("0x%08x%s", fdt32_to_cpu(p[j]), 925 j < (len/4 - 1) ? " " : ""); 926 printf(">"); 927 } 928 } else { /* anything else... hexdump */ 929 if (len > CMD_FDT_MAX_DUMP) 930 printf("* 0x%p [0x%08x]", data, len); 931 else { 932 const u8 *s; 933 934 printf("["); 935 for (j = 0, s = data; j < len; j++) 936 printf("%02x%s", s[j], j < len - 1 ? " " : ""); 937 printf("]"); 938 } 939 } 940 } 941 942 /****************************************************************************/ 943 944 /* 945 * Recursively print (a portion of) the working_fdt. The depth parameter 946 * determines how deeply nested the fdt is printed. 947 */ 948 static int fdt_print(const char *pathp, char *prop, int depth) 949 { 950 static char tabs[MAX_LEVEL+1] = 951 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" 952 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; 953 const void *nodep; /* property node pointer */ 954 int nodeoffset; /* node offset from libfdt */ 955 int nextoffset; /* next node offset from libfdt */ 956 uint32_t tag; /* tag */ 957 int len; /* length of the property */ 958 int level = 0; /* keep track of nesting level */ 959 const struct fdt_property *fdt_prop; 960 961 nodeoffset = fdt_path_offset (working_fdt, pathp); 962 if (nodeoffset < 0) { 963 /* 964 * Not found or something else bad happened. 965 */ 966 printf ("libfdt fdt_path_offset() returned %s\n", 967 fdt_strerror(nodeoffset)); 968 return 1; 969 } 970 /* 971 * The user passed in a property as well as node path. 972 * Print only the given property and then return. 973 */ 974 if (prop) { 975 nodep = fdt_getprop (working_fdt, nodeoffset, prop, &len); 976 if (len == 0) { 977 /* no property value */ 978 printf("%s %s\n", pathp, prop); 979 return 0; 980 } else if (nodep && len > 0) { 981 printf("%s = ", prop); 982 print_data (nodep, len); 983 printf("\n"); 984 return 0; 985 } else { 986 printf ("libfdt fdt_getprop(): %s\n", 987 fdt_strerror(len)); 988 return 1; 989 } 990 } 991 992 /* 993 * The user passed in a node path and no property, 994 * print the node and all subnodes. 995 */ 996 while(level >= 0) { 997 tag = fdt_next_tag(working_fdt, nodeoffset, &nextoffset); 998 switch(tag) { 999 case FDT_BEGIN_NODE: 1000 pathp = fdt_get_name(working_fdt, nodeoffset, NULL); 1001 if (level <= depth) { 1002 if (pathp == NULL) 1003 pathp = "/* NULL pointer error */"; 1004 if (*pathp == '\0') 1005 pathp = "/"; /* root is nameless */ 1006 printf("%s%s {\n", 1007 &tabs[MAX_LEVEL - level], pathp); 1008 } 1009 level++; 1010 if (level >= MAX_LEVEL) { 1011 printf("Nested too deep, aborting.\n"); 1012 return 1; 1013 } 1014 break; 1015 case FDT_END_NODE: 1016 level--; 1017 if (level <= depth) 1018 printf("%s};\n", &tabs[MAX_LEVEL - level]); 1019 if (level == 0) { 1020 level = -1; /* exit the loop */ 1021 } 1022 break; 1023 case FDT_PROP: 1024 fdt_prop = fdt_offset_ptr(working_fdt, nodeoffset, 1025 sizeof(*fdt_prop)); 1026 pathp = fdt_string(working_fdt, 1027 fdt32_to_cpu(fdt_prop->nameoff)); 1028 len = fdt32_to_cpu(fdt_prop->len); 1029 nodep = fdt_prop->data; 1030 if (len < 0) { 1031 printf ("libfdt fdt_getprop(): %s\n", 1032 fdt_strerror(len)); 1033 return 1; 1034 } else if (len == 0) { 1035 /* the property has no value */ 1036 if (level <= depth) 1037 printf("%s%s;\n", 1038 &tabs[MAX_LEVEL - level], 1039 pathp); 1040 } else { 1041 if (level <= depth) { 1042 printf("%s%s = ", 1043 &tabs[MAX_LEVEL - level], 1044 pathp); 1045 print_data (nodep, len); 1046 printf(";\n"); 1047 } 1048 } 1049 break; 1050 case FDT_NOP: 1051 printf("%s/* NOP */\n", &tabs[MAX_LEVEL - level]); 1052 break; 1053 case FDT_END: 1054 return 1; 1055 default: 1056 if (level <= depth) 1057 printf("Unknown tag 0x%08X\n", tag); 1058 return 1; 1059 } 1060 nodeoffset = nextoffset; 1061 } 1062 return 0; 1063 } 1064 1065 /********************************************************************/ 1066 #ifdef CONFIG_SYS_LONGHELP 1067 static char fdt_help_text[] = 1068 "addr [-c] <addr> [<length>] - Set the [control] fdt location to <addr>\n" 1069 #ifdef CONFIG_OF_LIBFDT_OVERLAY 1070 "fdt apply <addr> - Apply overlay to the DT\n" 1071 #endif 1072 #ifdef CONFIG_OF_BOARD_SETUP 1073 "fdt boardsetup - Do board-specific set up\n" 1074 #endif 1075 #ifdef CONFIG_OF_SYSTEM_SETUP 1076 "fdt systemsetup - Do system-specific set up\n" 1077 #endif 1078 "fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active\n" 1079 "fdt resize [<extrasize>] - Resize fdt to size + padding to 4k addr + some optional <extrasize> if needed\n" 1080 "fdt print <path> [<prop>] - Recursive print starting at <path>\n" 1081 "fdt list <path> [<prop>] - Print one level starting at <path>\n" 1082 "fdt get value <var> <path> <prop> - Get <property> and store in <var>\n" 1083 "fdt get name <var> <path> <index> - Get name of node <index> and store in <var>\n" 1084 "fdt get addr <var> <path> <prop> - Get start address of <property> and store in <var>\n" 1085 "fdt get size <var> <path> [<prop>] - Get size of [<property>] or num nodes and store in <var>\n" 1086 "fdt set <path> <prop> [<val>] - Set <property> [to <val>]\n" 1087 "fdt mknode <path> <node> - Create a new node after <path>\n" 1088 "fdt rm <path> [<prop>] - Delete the node or <property>\n" 1089 "fdt header - Display header info\n" 1090 "fdt bootcpu <id> - Set boot cpuid\n" 1091 "fdt memory <addr> <size> - Add/Update memory node\n" 1092 "fdt rsvmem print - Show current mem reserves\n" 1093 "fdt rsvmem add <addr> <size> - Add a mem reserve\n" 1094 "fdt rsvmem delete <index> - Delete a mem reserves\n" 1095 "fdt chosen [<start> <end>] - Add/update the /chosen branch in the tree\n" 1096 " <start>/<end> - initrd start/end addr\n" 1097 #if defined(CONFIG_FIT_SIGNATURE) 1098 "fdt checksign [<addr>] - check FIT signature\n" 1099 " <start> - addr of key blob\n" 1100 " default gd->fdt_blob\n" 1101 #endif 1102 "NOTE: Dereference aliases by omitting the leading '/', " 1103 "e.g. fdt print ethernet0."; 1104 #endif 1105 1106 U_BOOT_CMD( 1107 fdt, 255, 0, do_fdt, 1108 "flattened device tree utility commands", fdt_help_text 1109 ); 1110