1 /*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Semihalf under sponsorship from 6 * the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <stand.h> 34 #include <libfdt.h> 35 #include <fdt.h> 36 #include <sys/param.h> 37 #include <sys/linker.h> 38 #include <machine/elf.h> 39 40 #include "bootstrap.h" 41 #include "fdt_platform.h" 42 43 #ifdef DEBUG 44 #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 45 printf(fmt,##args); } while (0) 46 #else 47 #define debugf(fmt, args...) 48 #endif 49 50 #define FDT_CWD_LEN 256 51 #define FDT_MAX_DEPTH 12 52 53 #define FDT_PROP_SEP " = " 54 55 #define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l) 56 #define COPYIN(s,d,l) archsw.arch_copyin(s, d, l) 57 58 #define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb" 59 60 #define CMD_REQUIRES_BLOB 0x01 61 62 /* Location of FDT yet to be loaded. */ 63 /* This may be in read-only memory, so can't be manipulated directly. */ 64 static struct fdt_header *fdt_to_load = NULL; 65 /* Location of FDT on heap. */ 66 /* This is the copy we actually manipulate. */ 67 static struct fdt_header *fdtp = NULL; 68 /* Size of FDT blob */ 69 static size_t fdtp_size = 0; 70 /* Location of FDT in kernel or module. */ 71 /* This won't be set if FDT is loaded from disk or memory. */ 72 /* If it is set, we'll update it when fdt_copy() gets called. */ 73 static vm_offset_t fdtp_va = 0; 74 75 static int fdt_load_dtb(vm_offset_t va); 76 77 static int fdt_cmd_nyi(int argc, char *argv[]); 78 79 static int fdt_cmd_addr(int argc, char *argv[]); 80 static int fdt_cmd_mkprop(int argc, char *argv[]); 81 static int fdt_cmd_cd(int argc, char *argv[]); 82 static int fdt_cmd_hdr(int argc, char *argv[]); 83 static int fdt_cmd_ls(int argc, char *argv[]); 84 static int fdt_cmd_prop(int argc, char *argv[]); 85 static int fdt_cmd_pwd(int argc, char *argv[]); 86 static int fdt_cmd_rm(int argc, char *argv[]); 87 static int fdt_cmd_mknode(int argc, char *argv[]); 88 static int fdt_cmd_mres(int argc, char *argv[]); 89 90 typedef int cmdf_t(int, char *[]); 91 92 struct cmdtab { 93 const char *name; 94 cmdf_t *handler; 95 int flags; 96 }; 97 98 static const struct cmdtab commands[] = { 99 { "addr", &fdt_cmd_addr, 0 }, 100 { "alias", &fdt_cmd_nyi, 0 }, 101 { "cd", &fdt_cmd_cd, CMD_REQUIRES_BLOB }, 102 { "header", &fdt_cmd_hdr, CMD_REQUIRES_BLOB }, 103 { "ls", &fdt_cmd_ls, CMD_REQUIRES_BLOB }, 104 { "mknode", &fdt_cmd_mknode, CMD_REQUIRES_BLOB }, 105 { "mkprop", &fdt_cmd_mkprop, CMD_REQUIRES_BLOB }, 106 { "mres", &fdt_cmd_mres, CMD_REQUIRES_BLOB }, 107 { "prop", &fdt_cmd_prop, CMD_REQUIRES_BLOB }, 108 { "pwd", &fdt_cmd_pwd, CMD_REQUIRES_BLOB }, 109 { "rm", &fdt_cmd_rm, CMD_REQUIRES_BLOB }, 110 { NULL, NULL } 111 }; 112 113 static char cwd[FDT_CWD_LEN] = "/"; 114 115 static vm_offset_t 116 fdt_find_static_dtb() 117 { 118 Elf_Ehdr *ehdr; 119 Elf_Shdr *shdr; 120 Elf_Sym sym; 121 vm_offset_t strtab, symtab, fdt_start; 122 uint64_t offs; 123 struct preloaded_file *kfp; 124 struct file_metadata *md; 125 char *strp; 126 int i, sym_count; 127 128 debugf("fdt_find_static_dtb()\n"); 129 130 sym_count = symtab = strtab = 0; 131 strp = NULL; 132 133 offs = __elfN(relocation_offset); 134 135 kfp = file_findfile(NULL, NULL); 136 if (kfp == NULL) 137 return (0); 138 139 /* Locate the dynamic symbols and strtab. */ 140 md = file_findmetadata(kfp, MODINFOMD_ELFHDR); 141 if (md == NULL) 142 return (0); 143 ehdr = (Elf_Ehdr *)md->md_data; 144 145 md = file_findmetadata(kfp, MODINFOMD_SHDR); 146 if (md == NULL) 147 return (0); 148 shdr = (Elf_Shdr *)md->md_data; 149 150 for (i = 0; i < ehdr->e_shnum; ++i) { 151 if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) { 152 symtab = shdr[i].sh_addr + offs; 153 sym_count = shdr[i].sh_size / sizeof(Elf_Sym); 154 } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) { 155 strtab = shdr[i].sh_addr + offs; 156 } 157 } 158 159 /* 160 * The most efficient way to find a symbol would be to calculate a 161 * hash, find proper bucket and chain, and thus find a symbol. 162 * However, that would involve code duplication (e.g. for hash 163 * function). So we're using simpler and a bit slower way: we're 164 * iterating through symbols, searching for the one which name is 165 * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, 166 * we are eliminating symbols type of which is not STT_NOTYPE, or(and) 167 * those which binding attribute is not STB_GLOBAL. 168 */ 169 fdt_start = 0; 170 while (sym_count > 0 && fdt_start == 0) { 171 COPYOUT(symtab, &sym, sizeof(sym)); 172 symtab += sizeof(sym); 173 --sym_count; 174 if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || 175 ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) 176 continue; 177 strp = strdupout(strtab + sym.st_name); 178 if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) 179 fdt_start = (vm_offset_t)sym.st_value + offs; 180 free(strp); 181 } 182 return (fdt_start); 183 } 184 185 static int 186 fdt_load_dtb(vm_offset_t va) 187 { 188 struct fdt_header header; 189 int err; 190 191 debugf("fdt_load_dtb(0x%08jx)\n", (uintmax_t)va); 192 193 COPYOUT(va, &header, sizeof(header)); 194 err = fdt_check_header(&header); 195 if (err < 0) { 196 if (err == -FDT_ERR_BADVERSION) { 197 snprintf(command_errbuf, sizeof(command_errbuf), 198 "incompatible blob version: %d, should be: %d", 199 fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); 200 } else { 201 snprintf(command_errbuf, sizeof(command_errbuf), 202 "error validating blob: %s", fdt_strerror(err)); 203 } 204 return (1); 205 } 206 207 /* 208 * Release previous blob 209 */ 210 if (fdtp) 211 free(fdtp); 212 213 fdtp_size = fdt_totalsize(&header); 214 fdtp = malloc(fdtp_size); 215 216 if (fdtp == NULL) { 217 command_errmsg = "can't allocate memory for device tree copy"; 218 return (1); 219 } 220 221 fdtp_va = va; 222 COPYOUT(va, fdtp, fdtp_size); 223 debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size); 224 225 return (0); 226 } 227 228 int 229 fdt_load_dtb_addr(struct fdt_header *header) 230 { 231 int err; 232 233 debugf("fdt_load_dtb_addr(%p)\n", header); 234 235 fdtp_size = fdt_totalsize(header); 236 err = fdt_check_header(header); 237 if (err < 0) { 238 snprintf(command_errbuf, sizeof(command_errbuf), 239 "error validating blob: %s", fdt_strerror(err)); 240 return (err); 241 } 242 free(fdtp); 243 if ((fdtp = malloc(fdtp_size)) == NULL) { 244 command_errmsg = "can't allocate memory for device tree copy"; 245 return (1); 246 } 247 248 fdtp_va = 0; // Don't write this back into module or kernel. 249 bcopy(header, fdtp, fdtp_size); 250 return (0); 251 } 252 253 int 254 fdt_load_dtb_file(const char * filename) 255 { 256 struct preloaded_file *bfp, *oldbfp; 257 int err; 258 259 debugf("fdt_load_dtb_file(%s)\n", filename); 260 261 oldbfp = file_findfile(NULL, "dtb"); 262 263 /* Attempt to load and validate a new dtb from a file. */ 264 if ((bfp = file_loadraw(filename, "dtb", 1)) == NULL) { 265 snprintf(command_errbuf, sizeof(command_errbuf), 266 "failed to load file '%s'", filename); 267 return (1); 268 } 269 if ((err = fdt_load_dtb(bfp->f_addr)) != 0) { 270 file_discard(bfp); 271 return (err); 272 } 273 274 /* A new dtb was validated, discard any previous file. */ 275 if (oldbfp) 276 file_discard(oldbfp); 277 return (0); 278 } 279 280 static int 281 fdt_load_dtb_overlay(const char * filename) 282 { 283 struct preloaded_file *bfp; 284 struct fdt_header header; 285 int err; 286 287 debugf("fdt_load_dtb_overlay(%s)\n", filename); 288 289 /* Attempt to load and validate a new dtb from a file. */ 290 if ((bfp = file_loadraw(filename, "dtbo", 1)) == NULL) { 291 printf("failed to load file '%s'\n", filename); 292 return (1); 293 } 294 295 COPYOUT(bfp->f_addr, &header, sizeof(header)); 296 err = fdt_check_header(&header); 297 298 if (err < 0) { 299 file_discard(bfp); 300 if (err == -FDT_ERR_BADVERSION) 301 printf("incompatible blob version: %d, should be: %d\n", 302 fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); 303 304 else 305 printf("error validating blob: %s\n", 306 fdt_strerror(err)); 307 return (1); 308 } 309 310 return (0); 311 } 312 313 int 314 fdt_load_dtb_overlays(const char * filenames) 315 { 316 char *names; 317 char *name; 318 char *comaptr; 319 320 debugf("fdt_load_dtb_overlay(%s)\n", filenames); 321 322 names = strdup(filenames); 323 if (names == NULL) 324 return (1); 325 name = names; 326 do { 327 comaptr = strchr(name, ','); 328 if (comaptr) 329 *comaptr = '\0'; 330 fdt_load_dtb_overlay(name); 331 name = comaptr + 1; 332 } while(comaptr); 333 334 free(names); 335 return (0); 336 } 337 338 void 339 fdt_apply_overlays() 340 { 341 struct preloaded_file *fp; 342 size_t max_overlay_size, next_fdtp_size; 343 size_t current_fdtp_size; 344 void *current_fdtp; 345 void *new_fdtp; 346 void *next_fdtp; 347 void *overlay; 348 int rv; 349 350 if ((fdtp == NULL) || (fdtp_size == 0)) 351 return; 352 353 new_fdtp = NULL; 354 max_overlay_size = 0; 355 for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { 356 if (max_overlay_size < fp->f_size) 357 max_overlay_size = fp->f_size; 358 } 359 360 /* Nothing to apply */ 361 if (max_overlay_size == 0) 362 return; 363 364 overlay = malloc(max_overlay_size); 365 if (overlay == NULL) { 366 printf("failed to allocate memory for DTB blob with overlays\n"); 367 return; 368 } 369 current_fdtp = fdtp; 370 current_fdtp_size = fdtp_size; 371 for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { 372 printf("applying DTB overlay '%s'\n", fp->f_name); 373 next_fdtp_size = current_fdtp_size + fp->f_size; 374 next_fdtp = malloc(next_fdtp_size); 375 if (next_fdtp == NULL) { 376 /* 377 * Output warning, then move on to applying other 378 * overlays in case this one is simply too large. 379 */ 380 printf("failed to allocate memory for overlay base\n"); 381 continue; 382 } 383 rv = fdt_open_into(current_fdtp, next_fdtp, next_fdtp_size); 384 if (rv != 0) { 385 free(next_fdtp); 386 printf("failed to open base dtb into overlay base\n"); 387 continue; 388 } 389 COPYOUT(fp->f_addr, overlay, fp->f_size); 390 /* Both overlay and new_fdtp may be modified in place */ 391 rv = fdt_overlay_apply(next_fdtp, overlay); 392 if (rv == 0) { 393 /* Rotate next -> current */ 394 if (current_fdtp != fdtp) 395 free(current_fdtp); 396 current_fdtp = next_fdtp; 397 current_fdtp_size = next_fdtp_size; 398 } else { 399 /* 400 * Assume here that the base we tried to apply on is 401 * either trashed or in an inconsistent state. Trying to 402 * load it might work, but it's better to discard it and 403 * play it safe. */ 404 free(next_fdtp); 405 printf("failed to apply overlay: %s\n", 406 fdt_strerror(rv)); 407 } 408 } 409 /* We could have failed to apply all overlays; then we do nothing */ 410 if (current_fdtp != fdtp) { 411 free(fdtp); 412 fdtp = current_fdtp; 413 fdtp_size = current_fdtp_size; 414 } 415 free(overlay); 416 } 417 418 int 419 fdt_setup_fdtp() 420 { 421 struct preloaded_file *bfp; 422 vm_offset_t va; 423 424 debugf("fdt_setup_fdtp()\n"); 425 426 /* If we already loaded a file, use it. */ 427 if ((bfp = file_findfile(NULL, "dtb")) != NULL) { 428 if (fdt_load_dtb(bfp->f_addr) == 0) { 429 printf("Using DTB from loaded file '%s'.\n", 430 bfp->f_name); 431 return (0); 432 } 433 } 434 435 /* If we were given the address of a valid blob in memory, use it. */ 436 if (fdt_to_load != NULL) { 437 if (fdt_load_dtb_addr(fdt_to_load) == 0) { 438 printf("Using DTB from memory address %p.\n", 439 fdt_to_load); 440 return (0); 441 } 442 } 443 444 if (fdt_platform_load_dtb() == 0) 445 return (0); 446 447 /* If there is a dtb compiled into the kernel, use it. */ 448 if ((va = fdt_find_static_dtb()) != 0) { 449 if (fdt_load_dtb(va) == 0) { 450 printf("Using DTB compiled into kernel.\n"); 451 return (0); 452 } 453 } 454 455 command_errmsg = "No device tree blob found!\n"; 456 return (1); 457 } 458 459 #define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 460 (cellbuf), (lim), (cellsize), 0); 461 462 /* Force using base 16 */ 463 #define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 464 (cellbuf), (lim), (cellsize), 16); 465 466 static int 467 _fdt_strtovect(const char *str, void *cellbuf, int lim, unsigned char cellsize, 468 uint8_t base) 469 { 470 const char *buf = str; 471 const char *end = str + strlen(str) - 2; 472 uint32_t *u32buf = NULL; 473 uint8_t *u8buf = NULL; 474 int cnt = 0; 475 476 if (cellsize == sizeof(uint32_t)) 477 u32buf = (uint32_t *)cellbuf; 478 else 479 u8buf = (uint8_t *)cellbuf; 480 481 if (lim == 0) 482 return (0); 483 484 while (buf < end) { 485 486 /* Skip white whitespace(s)/separators */ 487 while (!isxdigit(*buf) && buf < end) 488 buf++; 489 490 if (u32buf != NULL) 491 u32buf[cnt] = 492 cpu_to_fdt32((uint32_t)strtol(buf, NULL, base)); 493 494 else 495 u8buf[cnt] = (uint8_t)strtol(buf, NULL, base); 496 497 if (cnt + 1 <= lim - 1) 498 cnt++; 499 else 500 break; 501 buf++; 502 /* Find another number */ 503 while ((isxdigit(*buf) || *buf == 'x') && buf < end) 504 buf++; 505 } 506 return (cnt); 507 } 508 509 void 510 fdt_fixup_ethernet(const char *str, char *ethstr, int len) 511 { 512 uint8_t tmp_addr[6]; 513 514 /* Convert macaddr string into a vector of uints */ 515 fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); 516 /* Set actual property to a value from vect */ 517 fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), 518 "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); 519 } 520 521 void 522 fdt_fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq) 523 { 524 int lo, o = 0, o2, maxo = 0, depth; 525 const uint32_t zero = 0; 526 527 /* We want to modify every subnode of /cpus */ 528 o = fdt_path_offset(fdtp, "/cpus"); 529 if (o < 0) 530 return; 531 532 /* maxo should contain offset of node next to /cpus */ 533 depth = 0; 534 maxo = o; 535 while (depth != -1) 536 maxo = fdt_next_node(fdtp, maxo, &depth); 537 538 /* Find CPU frequency properties */ 539 o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency", 540 &zero, sizeof(uint32_t)); 541 542 o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero, 543 sizeof(uint32_t)); 544 545 lo = MIN(o, o2); 546 547 while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) { 548 549 o = fdt_node_offset_by_prop_value(fdtp, lo, 550 "clock-frequency", &zero, sizeof(uint32_t)); 551 552 o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency", 553 &zero, sizeof(uint32_t)); 554 555 /* We're only interested in /cpus subnode(s) */ 556 if (lo > maxo) 557 break; 558 559 fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency", 560 (uint32_t)cpufreq); 561 562 fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency", 563 (uint32_t)busfreq); 564 565 lo = MIN(o, o2); 566 } 567 } 568 569 #ifdef notyet 570 static int 571 fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) 572 { 573 int cells_in_tuple, i, tuples, tuple_size; 574 uint32_t cur_start, cur_size; 575 576 cells_in_tuple = (addr_cells + size_cells); 577 tuple_size = cells_in_tuple * sizeof(uint32_t); 578 tuples = len / tuple_size; 579 if (tuples == 0) 580 return (EINVAL); 581 582 for (i = 0; i < tuples; i++) { 583 if (addr_cells == 2) 584 cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); 585 else 586 cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); 587 588 if (size_cells == 2) 589 cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); 590 else 591 cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); 592 593 if (cur_size == 0) 594 return (EINVAL); 595 596 debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", 597 i, cur_start, cur_size); 598 } 599 return (0); 600 } 601 #endif 602 603 void 604 fdt_fixup_memory(struct fdt_mem_region *region, size_t num) 605 { 606 struct fdt_mem_region *curmr; 607 uint32_t addr_cells, size_cells; 608 uint32_t *addr_cellsp, *size_cellsp; 609 int err, i, len, memory, root; 610 size_t realmrno; 611 uint8_t *buf, *sb; 612 uint64_t rstart, rsize; 613 int reserved; 614 615 root = fdt_path_offset(fdtp, "/"); 616 if (root < 0) { 617 sprintf(command_errbuf, "Could not find root node !"); 618 return; 619 } 620 621 memory = fdt_path_offset(fdtp, "/memory"); 622 if (memory <= 0) { 623 /* Create proper '/memory' node. */ 624 memory = fdt_add_subnode(fdtp, root, "memory"); 625 if (memory <= 0) { 626 snprintf(command_errbuf, sizeof(command_errbuf), 627 "Could not fixup '/memory' " 628 "node, error code : %d!\n", memory); 629 return; 630 } 631 632 err = fdt_setprop(fdtp, memory, "device_type", "memory", 633 sizeof("memory")); 634 635 if (err < 0) 636 return; 637 } 638 639 addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", 640 NULL); 641 size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); 642 643 if (addr_cellsp == NULL || size_cellsp == NULL) { 644 snprintf(command_errbuf, sizeof(command_errbuf), 645 "Could not fixup '/memory' node : " 646 "%s %s property not found in root node!\n", 647 (!addr_cellsp) ? "#address-cells" : "", 648 (!size_cellsp) ? "#size-cells" : ""); 649 return; 650 } 651 652 addr_cells = fdt32_to_cpu(*addr_cellsp); 653 size_cells = fdt32_to_cpu(*size_cellsp); 654 655 /* 656 * Convert memreserve data to memreserve property 657 * Check if property already exists 658 */ 659 reserved = fdt_num_mem_rsv(fdtp); 660 if (reserved && 661 (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) { 662 len = (addr_cells + size_cells) * reserved * sizeof(uint32_t); 663 sb = buf = (uint8_t *)malloc(len); 664 if (!buf) 665 return; 666 667 bzero(buf, len); 668 669 for (i = 0; i < reserved; i++) { 670 if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize)) 671 break; 672 if (rsize) { 673 /* Ensure endianness, and put cells into a buffer */ 674 if (addr_cells == 2) 675 *(uint64_t *)buf = 676 cpu_to_fdt64(rstart); 677 else 678 *(uint32_t *)buf = 679 cpu_to_fdt32(rstart); 680 681 buf += sizeof(uint32_t) * addr_cells; 682 if (size_cells == 2) 683 *(uint64_t *)buf = 684 cpu_to_fdt64(rsize); 685 else 686 *(uint32_t *)buf = 687 cpu_to_fdt32(rsize); 688 689 buf += sizeof(uint32_t) * size_cells; 690 } 691 } 692 693 /* Set property */ 694 if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0) 695 printf("Could not fixup 'memreserve' property.\n"); 696 697 free(sb); 698 } 699 700 /* Count valid memory regions entries in sysinfo. */ 701 realmrno = num; 702 for (i = 0; i < num; i++) 703 if (region[i].start == 0 && region[i].size == 0) 704 realmrno--; 705 706 if (realmrno == 0) { 707 sprintf(command_errbuf, "Could not fixup '/memory' node : " 708 "sysinfo doesn't contain valid memory regions info!\n"); 709 return; 710 } 711 712 len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); 713 sb = buf = (uint8_t *)malloc(len); 714 if (!buf) 715 return; 716 717 bzero(buf, len); 718 719 for (i = 0; i < num; i++) { 720 curmr = ®ion[i]; 721 if (curmr->size != 0) { 722 /* Ensure endianness, and put cells into a buffer */ 723 if (addr_cells == 2) 724 *(uint64_t *)buf = 725 cpu_to_fdt64(curmr->start); 726 else 727 *(uint32_t *)buf = 728 cpu_to_fdt32(curmr->start); 729 730 buf += sizeof(uint32_t) * addr_cells; 731 if (size_cells == 2) 732 *(uint64_t *)buf = 733 cpu_to_fdt64(curmr->size); 734 else 735 *(uint32_t *)buf = 736 cpu_to_fdt32(curmr->size); 737 738 buf += sizeof(uint32_t) * size_cells; 739 } 740 } 741 742 /* Set property */ 743 if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) 744 sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); 745 746 free(sb); 747 } 748 749 void 750 fdt_fixup_stdout(const char *str) 751 { 752 char *ptr; 753 int serialno; 754 int len, no, sero; 755 const struct fdt_property *prop; 756 char *tmp[10]; 757 758 ptr = (char *)str + strlen(str) - 1; 759 while (ptr > str && isdigit(*(str - 1))) 760 str--; 761 762 if (ptr == str) 763 return; 764 765 serialno = (int)strtol(ptr, NULL, 0); 766 no = fdt_path_offset(fdtp, "/chosen"); 767 if (no < 0) 768 return; 769 770 prop = fdt_get_property(fdtp, no, "stdout", &len); 771 772 /* If /chosen/stdout does not extist, create it */ 773 if (prop == NULL || (prop != NULL && len == 0)) { 774 775 bzero(tmp, 10 * sizeof(char)); 776 strcpy((char *)&tmp, "serial"); 777 if (strlen(ptr) > 3) 778 /* Serial number too long */ 779 return; 780 781 strncpy((char *)tmp + 6, ptr, 3); 782 sero = fdt_path_offset(fdtp, (const char *)tmp); 783 if (sero < 0) 784 /* 785 * If serial device we're trying to assign 786 * stdout to doesn't exist in DT -- return. 787 */ 788 return; 789 790 fdt_setprop(fdtp, no, "stdout", &tmp, 791 strlen((char *)&tmp) + 1); 792 fdt_setprop(fdtp, no, "stdin", &tmp, 793 strlen((char *)&tmp) + 1); 794 } 795 } 796 797 /* 798 * Locate the blob, fix it up and return its location. 799 */ 800 static int 801 fdt_fixup(void) 802 { 803 int chosen, len; 804 805 len = 0; 806 807 debugf("fdt_fixup()\n"); 808 809 if (fdtp == NULL && fdt_setup_fdtp() != 0) 810 return (0); 811 812 /* Create /chosen node (if not exists) */ 813 if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == 814 -FDT_ERR_NOTFOUND) 815 chosen = fdt_add_subnode(fdtp, 0, "chosen"); 816 817 /* Value assigned to fixup-applied does not matter. */ 818 if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) 819 return (1); 820 821 fdt_platform_fixups(); 822 823 fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); 824 return (1); 825 } 826 827 /* 828 * Copy DTB blob to specified location and return size 829 */ 830 int 831 fdt_copy(vm_offset_t va) 832 { 833 int err; 834 debugf("fdt_copy va 0x%08x\n", va); 835 if (fdtp == NULL) { 836 err = fdt_setup_fdtp(); 837 if (err) { 838 printf("No valid device tree blob found!\n"); 839 return (0); 840 } 841 } 842 843 if (fdt_fixup() == 0) 844 return (0); 845 846 if (fdtp_va != 0) { 847 /* Overwrite the FDT with the fixed version. */ 848 /* XXX Is this really appropriate? */ 849 COPYIN(fdtp, fdtp_va, fdtp_size); 850 } 851 COPYIN(fdtp, va, fdtp_size); 852 return (fdtp_size); 853 } 854 855 856 857 int 858 command_fdt_internal(int argc, char *argv[]) 859 { 860 cmdf_t *cmdh; 861 int flags; 862 char *cmd; 863 int i, err; 864 865 if (argc < 2) { 866 command_errmsg = "usage is 'fdt <command> [<args>]"; 867 return (CMD_ERROR); 868 } 869 870 /* 871 * Validate fdt <command>. 872 */ 873 cmd = strdup(argv[1]); 874 i = 0; 875 cmdh = NULL; 876 while (!(commands[i].name == NULL)) { 877 if (strcmp(cmd, commands[i].name) == 0) { 878 /* found it */ 879 cmdh = commands[i].handler; 880 flags = commands[i].flags; 881 break; 882 } 883 i++; 884 } 885 if (cmdh == NULL) { 886 command_errmsg = "unknown command"; 887 return (CMD_ERROR); 888 } 889 890 if (flags & CMD_REQUIRES_BLOB) { 891 /* 892 * Check if uboot env vars were parsed already. If not, do it now. 893 */ 894 if (fdt_fixup() == 0) 895 return (CMD_ERROR); 896 } 897 898 /* 899 * Call command handler. 900 */ 901 err = (*cmdh)(argc, argv); 902 903 return (err); 904 } 905 906 static int 907 fdt_cmd_addr(int argc, char *argv[]) 908 { 909 struct preloaded_file *fp; 910 struct fdt_header *hdr; 911 const char *addr; 912 char *cp; 913 914 fdt_to_load = NULL; 915 916 if (argc > 2) 917 addr = argv[2]; 918 else { 919 sprintf(command_errbuf, "no address specified"); 920 return (CMD_ERROR); 921 } 922 923 hdr = (struct fdt_header *)strtoul(addr, &cp, 16); 924 if (cp == addr) { 925 snprintf(command_errbuf, sizeof(command_errbuf), 926 "Invalid address: %s", addr); 927 return (CMD_ERROR); 928 } 929 930 while ((fp = file_findfile(NULL, "dtb")) != NULL) { 931 file_discard(fp); 932 } 933 934 fdt_to_load = hdr; 935 return (CMD_OK); 936 } 937 938 static int 939 fdt_cmd_cd(int argc, char *argv[]) 940 { 941 char *path; 942 char tmp[FDT_CWD_LEN]; 943 int len, o; 944 945 path = (argc > 2) ? argv[2] : "/"; 946 947 if (path[0] == '/') { 948 len = strlen(path); 949 if (len >= FDT_CWD_LEN) 950 goto fail; 951 } else { 952 /* Handle path specification relative to cwd */ 953 len = strlen(cwd) + strlen(path) + 1; 954 if (len >= FDT_CWD_LEN) 955 goto fail; 956 957 strcpy(tmp, cwd); 958 strcat(tmp, "/"); 959 strcat(tmp, path); 960 path = tmp; 961 } 962 963 o = fdt_path_offset(fdtp, path); 964 if (o < 0) { 965 snprintf(command_errbuf, sizeof(command_errbuf), 966 "could not find node: '%s'", path); 967 return (CMD_ERROR); 968 } 969 970 strcpy(cwd, path); 971 return (CMD_OK); 972 973 fail: 974 snprintf(command_errbuf, sizeof(command_errbuf), 975 "path too long: %d, max allowed: %d", len, FDT_CWD_LEN - 1); 976 return (CMD_ERROR); 977 } 978 979 static int 980 fdt_cmd_hdr(int argc __unused, char *argv[] __unused) 981 { 982 char line[80]; 983 int ver; 984 985 if (fdtp == NULL) { 986 command_errmsg = "no device tree blob pointer?!"; 987 return (CMD_ERROR); 988 } 989 990 ver = fdt_version(fdtp); 991 pager_open(); 992 sprintf(line, "\nFlattened device tree header (%p):\n", fdtp); 993 if (pager_output(line)) 994 goto out; 995 sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); 996 if (pager_output(line)) 997 goto out; 998 sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); 999 if (pager_output(line)) 1000 goto out; 1001 sprintf(line, " off_dt_struct = 0x%08x\n", 1002 fdt_off_dt_struct(fdtp)); 1003 if (pager_output(line)) 1004 goto out; 1005 sprintf(line, " off_dt_strings = 0x%08x\n", 1006 fdt_off_dt_strings(fdtp)); 1007 if (pager_output(line)) 1008 goto out; 1009 sprintf(line, " off_mem_rsvmap = 0x%08x\n", 1010 fdt_off_mem_rsvmap(fdtp)); 1011 if (pager_output(line)) 1012 goto out; 1013 sprintf(line, " version = %d\n", ver); 1014 if (pager_output(line)) 1015 goto out; 1016 sprintf(line, " last compatible version = %d\n", 1017 fdt_last_comp_version(fdtp)); 1018 if (pager_output(line)) 1019 goto out; 1020 if (ver >= 2) { 1021 sprintf(line, " boot_cpuid = %d\n", 1022 fdt_boot_cpuid_phys(fdtp)); 1023 if (pager_output(line)) 1024 goto out; 1025 } 1026 if (ver >= 3) { 1027 sprintf(line, " size_dt_strings = %d\n", 1028 fdt_size_dt_strings(fdtp)); 1029 if (pager_output(line)) 1030 goto out; 1031 } 1032 if (ver >= 17) { 1033 sprintf(line, " size_dt_struct = %d\n", 1034 fdt_size_dt_struct(fdtp)); 1035 if (pager_output(line)) 1036 goto out; 1037 } 1038 out: 1039 pager_close(); 1040 1041 return (CMD_OK); 1042 } 1043 1044 static int 1045 fdt_cmd_ls(int argc, char *argv[]) 1046 { 1047 const char *prevname[FDT_MAX_DEPTH] = { NULL }; 1048 const char *name; 1049 char *path; 1050 int i, o, depth; 1051 1052 path = (argc > 2) ? argv[2] : NULL; 1053 if (path == NULL) 1054 path = cwd; 1055 1056 o = fdt_path_offset(fdtp, path); 1057 if (o < 0) { 1058 snprintf(command_errbuf, sizeof(command_errbuf), 1059 "could not find node: '%s'", path); 1060 return (CMD_ERROR); 1061 } 1062 1063 for (depth = 0; 1064 (o >= 0) && (depth >= 0); 1065 o = fdt_next_node(fdtp, o, &depth)) { 1066 1067 name = fdt_get_name(fdtp, o, NULL); 1068 1069 if (depth > FDT_MAX_DEPTH) { 1070 printf("max depth exceeded: %d\n", depth); 1071 continue; 1072 } 1073 1074 prevname[depth] = name; 1075 1076 /* Skip root (i = 1) when printing devices */ 1077 for (i = 1; i <= depth; i++) { 1078 if (prevname[i] == NULL) 1079 break; 1080 1081 if (strcmp(cwd, "/") == 0) 1082 printf("/"); 1083 printf("%s", prevname[i]); 1084 } 1085 printf("\n"); 1086 } 1087 1088 return (CMD_OK); 1089 } 1090 1091 static __inline int 1092 isprint(int c) 1093 { 1094 1095 return (c >= ' ' && c <= 0x7e); 1096 } 1097 1098 static int 1099 fdt_isprint(const void *data, int len, int *count) 1100 { 1101 const char *d; 1102 char ch; 1103 int yesno, i; 1104 1105 if (len == 0) 1106 return (0); 1107 1108 d = (const char *)data; 1109 if (d[len - 1] != '\0') 1110 return (0); 1111 1112 *count = 0; 1113 yesno = 1; 1114 for (i = 0; i < len; i++) { 1115 ch = *(d + i); 1116 if (isprint(ch) || (ch == '\0' && i > 0)) { 1117 /* Count strings */ 1118 if (ch == '\0') 1119 (*count)++; 1120 continue; 1121 } 1122 1123 yesno = 0; 1124 break; 1125 } 1126 1127 return (yesno); 1128 } 1129 1130 static int 1131 fdt_data_str(const void *data, int len, int count, char **buf) 1132 { 1133 char *b, *tmp; 1134 const char *d; 1135 int buf_len, i, l; 1136 1137 /* 1138 * Calculate the length for the string and allocate memory. 1139 * 1140 * Note that 'len' already includes at least one terminator. 1141 */ 1142 buf_len = len; 1143 if (count > 1) { 1144 /* 1145 * Each token had already a terminator buried in 'len', but we 1146 * only need one eventually, don't count space for these. 1147 */ 1148 buf_len -= count - 1; 1149 1150 /* Each consecutive token requires a ", " separator. */ 1151 buf_len += count * 2; 1152 } 1153 1154 /* Add some space for surrounding double quotes. */ 1155 buf_len += count * 2; 1156 1157 /* Note that string being put in 'tmp' may be as big as 'buf_len'. */ 1158 b = (char *)malloc(buf_len); 1159 tmp = (char *)malloc(buf_len); 1160 if (b == NULL) 1161 goto error; 1162 1163 if (tmp == NULL) { 1164 free(b); 1165 goto error; 1166 } 1167 1168 b[0] = '\0'; 1169 1170 /* 1171 * Now that we have space, format the string. 1172 */ 1173 i = 0; 1174 do { 1175 d = (const char *)data + i; 1176 l = strlen(d) + 1; 1177 1178 sprintf(tmp, "\"%s\"%s", d, 1179 (i + l) < len ? ", " : ""); 1180 strcat(b, tmp); 1181 1182 i += l; 1183 1184 } while (i < len); 1185 *buf = b; 1186 1187 free(tmp); 1188 1189 return (0); 1190 error: 1191 return (1); 1192 } 1193 1194 static int 1195 fdt_data_cell(const void *data, int len, char **buf) 1196 { 1197 char *b, *tmp; 1198 const uint32_t *c; 1199 int count, i, l; 1200 1201 /* Number of cells */ 1202 count = len / 4; 1203 1204 /* 1205 * Calculate the length for the string and allocate memory. 1206 */ 1207 1208 /* Each byte translates to 2 output characters */ 1209 l = len * 2; 1210 if (count > 1) { 1211 /* Each consecutive cell requires a " " separator. */ 1212 l += (count - 1) * 1; 1213 } 1214 /* Each cell will have a "0x" prefix */ 1215 l += count * 2; 1216 /* Space for surrounding <> and terminator */ 1217 l += 3; 1218 1219 b = (char *)malloc(l); 1220 tmp = (char *)malloc(l); 1221 if (b == NULL) 1222 goto error; 1223 1224 if (tmp == NULL) { 1225 free(b); 1226 goto error; 1227 } 1228 1229 b[0] = '\0'; 1230 strcat(b, "<"); 1231 1232 for (i = 0; i < len; i += 4) { 1233 c = (const uint32_t *)((const uint8_t *)data + i); 1234 sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c), 1235 i < (len - 4) ? " " : ""); 1236 strcat(b, tmp); 1237 } 1238 strcat(b, ">"); 1239 *buf = b; 1240 1241 free(tmp); 1242 1243 return (0); 1244 error: 1245 return (1); 1246 } 1247 1248 static int 1249 fdt_data_bytes(const void *data, int len, char **buf) 1250 { 1251 char *b, *tmp; 1252 const char *d; 1253 int i, l; 1254 1255 /* 1256 * Calculate the length for the string and allocate memory. 1257 */ 1258 1259 /* Each byte translates to 2 output characters */ 1260 l = len * 2; 1261 if (len > 1) 1262 /* Each consecutive byte requires a " " separator. */ 1263 l += (len - 1) * 1; 1264 /* Each byte will have a "0x" prefix */ 1265 l += len * 2; 1266 /* Space for surrounding [] and terminator. */ 1267 l += 3; 1268 1269 b = (char *)malloc(l); 1270 tmp = (char *)malloc(l); 1271 if (b == NULL) 1272 goto error; 1273 1274 if (tmp == NULL) { 1275 free(b); 1276 goto error; 1277 } 1278 1279 b[0] = '\0'; 1280 strcat(b, "["); 1281 1282 for (i = 0, d = data; i < len; i++) { 1283 sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : ""); 1284 strcat(b, tmp); 1285 } 1286 strcat(b, "]"); 1287 *buf = b; 1288 1289 free(tmp); 1290 1291 return (0); 1292 error: 1293 return (1); 1294 } 1295 1296 static int 1297 fdt_data_fmt(const void *data, int len, char **buf) 1298 { 1299 int count; 1300 1301 if (len == 0) { 1302 *buf = NULL; 1303 return (1); 1304 } 1305 1306 if (fdt_isprint(data, len, &count)) 1307 return (fdt_data_str(data, len, count, buf)); 1308 1309 else if ((len % 4) == 0) 1310 return (fdt_data_cell(data, len, buf)); 1311 1312 else 1313 return (fdt_data_bytes(data, len, buf)); 1314 } 1315 1316 static int 1317 fdt_prop(int offset) 1318 { 1319 char *line, *buf; 1320 const struct fdt_property *prop; 1321 const char *name; 1322 const void *data; 1323 int len, rv; 1324 1325 line = NULL; 1326 prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop)); 1327 if (prop == NULL) 1328 return (1); 1329 1330 name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); 1331 len = fdt32_to_cpu(prop->len); 1332 1333 rv = 0; 1334 buf = NULL; 1335 if (len == 0) { 1336 /* Property without value */ 1337 line = (char *)malloc(strlen(name) + 2); 1338 if (line == NULL) { 1339 rv = 2; 1340 goto out2; 1341 } 1342 sprintf(line, "%s\n", name); 1343 goto out1; 1344 } 1345 1346 /* 1347 * Process property with value 1348 */ 1349 data = prop->data; 1350 1351 if (fdt_data_fmt(data, len, &buf) != 0) { 1352 rv = 3; 1353 goto out2; 1354 } 1355 1356 line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) + 1357 strlen(buf) + 2); 1358 if (line == NULL) { 1359 sprintf(command_errbuf, "could not allocate space for string"); 1360 rv = 4; 1361 goto out2; 1362 } 1363 1364 sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf); 1365 1366 out1: 1367 pager_open(); 1368 pager_output(line); 1369 pager_close(); 1370 1371 out2: 1372 if (buf) 1373 free(buf); 1374 1375 if (line) 1376 free(line); 1377 1378 return (rv); 1379 } 1380 1381 static int 1382 fdt_modprop(int nodeoff, char *propname, void *value, char mode) 1383 { 1384 uint32_t cells[100]; 1385 const char *buf; 1386 int len, rv; 1387 const struct fdt_property *p; 1388 1389 p = fdt_get_property(fdtp, nodeoff, propname, NULL); 1390 1391 if (p != NULL) { 1392 if (mode == 1) { 1393 /* Adding inexistant value in mode 1 is forbidden */ 1394 sprintf(command_errbuf, "property already exists!"); 1395 return (CMD_ERROR); 1396 } 1397 } else if (mode == 0) { 1398 sprintf(command_errbuf, "property does not exist!"); 1399 return (CMD_ERROR); 1400 } 1401 len = strlen(value); 1402 rv = 0; 1403 buf = value; 1404 1405 switch (*buf) { 1406 case '&': 1407 /* phandles */ 1408 break; 1409 case '<': 1410 /* Data cells */ 1411 len = fdt_strtovect(buf, (void *)&cells, 100, 1412 sizeof(uint32_t)); 1413 1414 rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1415 len * sizeof(uint32_t)); 1416 break; 1417 case '[': 1418 /* Data bytes */ 1419 len = fdt_strtovect(buf, (void *)&cells, 100, 1420 sizeof(uint8_t)); 1421 1422 rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1423 len * sizeof(uint8_t)); 1424 break; 1425 case '"': 1426 default: 1427 /* Default -- string */ 1428 rv = fdt_setprop_string(fdtp, nodeoff, propname, value); 1429 break; 1430 } 1431 1432 if (rv != 0) { 1433 if (rv == -FDT_ERR_NOSPACE) 1434 sprintf(command_errbuf, 1435 "Device tree blob is too small!\n"); 1436 else 1437 sprintf(command_errbuf, 1438 "Could not add/modify property!\n"); 1439 } 1440 return (rv); 1441 } 1442 1443 /* Merge strings from argv into a single string */ 1444 static int 1445 fdt_merge_strings(int argc, char *argv[], int start, char **buffer) 1446 { 1447 char *buf; 1448 int i, idx, sz; 1449 1450 *buffer = NULL; 1451 sz = 0; 1452 1453 for (i = start; i < argc; i++) 1454 sz += strlen(argv[i]); 1455 1456 /* Additional bytes for whitespaces between args */ 1457 sz += argc - start; 1458 1459 buf = (char *)malloc(sizeof(char) * sz); 1460 if (buf == NULL) { 1461 sprintf(command_errbuf, "could not allocate space " 1462 "for string"); 1463 return (1); 1464 } 1465 bzero(buf, sizeof(char) * sz); 1466 1467 idx = 0; 1468 for (i = start, idx = 0; i < argc; i++) { 1469 strcpy(buf + idx, argv[i]); 1470 idx += strlen(argv[i]); 1471 buf[idx] = ' '; 1472 idx++; 1473 } 1474 buf[sz - 1] = '\0'; 1475 *buffer = buf; 1476 return (0); 1477 } 1478 1479 /* Extract offset and name of node/property from a given path */ 1480 static int 1481 fdt_extract_nameloc(char **pathp, char **namep, int *nodeoff) 1482 { 1483 int o; 1484 char *path = *pathp, *name = NULL, *subpath = NULL; 1485 1486 subpath = strrchr(path, '/'); 1487 if (subpath == NULL) { 1488 o = fdt_path_offset(fdtp, cwd); 1489 name = path; 1490 path = (char *)&cwd; 1491 } else { 1492 *subpath = '\0'; 1493 if (strlen(path) == 0) 1494 path = cwd; 1495 1496 name = subpath + 1; 1497 o = fdt_path_offset(fdtp, path); 1498 } 1499 1500 if (strlen(name) == 0) { 1501 sprintf(command_errbuf, "name not specified"); 1502 return (1); 1503 } 1504 if (o < 0) { 1505 snprintf(command_errbuf, sizeof(command_errbuf), 1506 "could not find node: '%s'", path); 1507 return (1); 1508 } 1509 *namep = name; 1510 *nodeoff = o; 1511 *pathp = path; 1512 return (0); 1513 } 1514 1515 static int 1516 fdt_cmd_prop(int argc, char *argv[]) 1517 { 1518 char *path, *propname, *value; 1519 int o, next, depth, rv; 1520 uint32_t tag; 1521 1522 path = (argc > 2) ? argv[2] : NULL; 1523 1524 value = NULL; 1525 1526 if (argc > 3) { 1527 /* Merge property value strings into one */ 1528 if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1529 return (CMD_ERROR); 1530 } else 1531 value = NULL; 1532 1533 if (path == NULL) 1534 path = cwd; 1535 1536 rv = CMD_OK; 1537 1538 if (value) { 1539 /* If value is specified -- try to modify prop. */ 1540 if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1541 return (CMD_ERROR); 1542 1543 rv = fdt_modprop(o, propname, value, 0); 1544 if (rv) 1545 return (CMD_ERROR); 1546 return (CMD_OK); 1547 1548 } 1549 /* User wants to display properties */ 1550 o = fdt_path_offset(fdtp, path); 1551 1552 if (o < 0) { 1553 snprintf(command_errbuf, sizeof(command_errbuf), 1554 "could not find node: '%s'", path); 1555 rv = CMD_ERROR; 1556 goto out; 1557 } 1558 1559 depth = 0; 1560 while (depth >= 0) { 1561 tag = fdt_next_tag(fdtp, o, &next); 1562 switch (tag) { 1563 case FDT_NOP: 1564 break; 1565 case FDT_PROP: 1566 if (depth > 1) 1567 /* Don't process properties of nested nodes */ 1568 break; 1569 1570 if (fdt_prop(o) != 0) { 1571 sprintf(command_errbuf, "could not process " 1572 "property"); 1573 rv = CMD_ERROR; 1574 goto out; 1575 } 1576 break; 1577 case FDT_BEGIN_NODE: 1578 depth++; 1579 if (depth > FDT_MAX_DEPTH) { 1580 printf("warning: nesting too deep: %d\n", 1581 depth); 1582 goto out; 1583 } 1584 break; 1585 case FDT_END_NODE: 1586 depth--; 1587 if (depth == 0) 1588 /* 1589 * This is the end of our starting node, force 1590 * the loop finish. 1591 */ 1592 depth--; 1593 break; 1594 } 1595 o = next; 1596 } 1597 out: 1598 return (rv); 1599 } 1600 1601 static int 1602 fdt_cmd_mkprop(int argc, char *argv[]) 1603 { 1604 int o; 1605 char *path, *propname, *value; 1606 1607 path = (argc > 2) ? argv[2] : NULL; 1608 1609 value = NULL; 1610 1611 if (argc > 3) { 1612 /* Merge property value strings into one */ 1613 if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1614 return (CMD_ERROR); 1615 } else 1616 value = NULL; 1617 1618 if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1619 return (CMD_ERROR); 1620 1621 if (fdt_modprop(o, propname, value, 1)) 1622 return (CMD_ERROR); 1623 1624 return (CMD_OK); 1625 } 1626 1627 static int 1628 fdt_cmd_rm(int argc, char *argv[]) 1629 { 1630 int o, rv; 1631 char *path = NULL, *propname; 1632 1633 if (argc > 2) 1634 path = argv[2]; 1635 else { 1636 sprintf(command_errbuf, "no node/property name specified"); 1637 return (CMD_ERROR); 1638 } 1639 1640 o = fdt_path_offset(fdtp, path); 1641 if (o < 0) { 1642 /* If node not found -- try to find & delete property */ 1643 if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1644 return (CMD_ERROR); 1645 1646 if ((rv = fdt_delprop(fdtp, o, propname)) != 0) { 1647 snprintf(command_errbuf, sizeof(command_errbuf), 1648 "could not delete %s\n", 1649 (rv == -FDT_ERR_NOTFOUND) ? 1650 "(property/node does not exist)" : ""); 1651 return (CMD_ERROR); 1652 1653 } else 1654 return (CMD_OK); 1655 } 1656 /* If node exists -- remove node */ 1657 rv = fdt_del_node(fdtp, o); 1658 if (rv) { 1659 sprintf(command_errbuf, "could not delete node"); 1660 return (CMD_ERROR); 1661 } 1662 return (CMD_OK); 1663 } 1664 1665 static int 1666 fdt_cmd_mknode(int argc, char *argv[]) 1667 { 1668 int o, rv; 1669 char *path = NULL, *nodename = NULL; 1670 1671 if (argc > 2) 1672 path = argv[2]; 1673 else { 1674 sprintf(command_errbuf, "no node name specified"); 1675 return (CMD_ERROR); 1676 } 1677 1678 if (fdt_extract_nameloc(&path, &nodename, &o) != 0) 1679 return (CMD_ERROR); 1680 1681 rv = fdt_add_subnode(fdtp, o, nodename); 1682 1683 if (rv < 0) { 1684 if (rv == -FDT_ERR_NOSPACE) 1685 sprintf(command_errbuf, 1686 "Device tree blob is too small!\n"); 1687 else 1688 sprintf(command_errbuf, 1689 "Could not add node!\n"); 1690 return (CMD_ERROR); 1691 } 1692 return (CMD_OK); 1693 } 1694 1695 static int 1696 fdt_cmd_pwd(int argc, char *argv[]) 1697 { 1698 char line[FDT_CWD_LEN]; 1699 1700 pager_open(); 1701 sprintf(line, "%s\n", cwd); 1702 pager_output(line); 1703 pager_close(); 1704 return (CMD_OK); 1705 } 1706 1707 static int 1708 fdt_cmd_mres(int argc, char *argv[]) 1709 { 1710 uint64_t start, size; 1711 int i, total; 1712 char line[80]; 1713 1714 pager_open(); 1715 total = fdt_num_mem_rsv(fdtp); 1716 if (total > 0) { 1717 if (pager_output("Reserved memory regions:\n")) 1718 goto out; 1719 for (i = 0; i < total; i++) { 1720 fdt_get_mem_rsv(fdtp, i, &start, &size); 1721 sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", 1722 i, start, size); 1723 if (pager_output(line)) 1724 goto out; 1725 } 1726 } else 1727 pager_output("No reserved memory regions\n"); 1728 out: 1729 pager_close(); 1730 1731 return (CMD_OK); 1732 } 1733 1734 static int 1735 fdt_cmd_nyi(int argc, char *argv[]) 1736 { 1737 1738 printf("command not yet implemented\n"); 1739 return (CMD_ERROR); 1740 } 1741