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