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