fdt_loader_cmd.c revision 247045
1246586Sdelphij/*- 2246586Sdelphij * Copyright (c) 2009-2010 The FreeBSD Foundation 3246586Sdelphij * All rights reserved. 4246586Sdelphij * 5246586Sdelphij * This software was developed by Semihalf under sponsorship from 6246586Sdelphij * the FreeBSD Foundation. 7246586Sdelphij * 8246586Sdelphij * Redistribution and use in source and binary forms, with or without 9246586Sdelphij * modification, are permitted provided that the following conditions 10246586Sdelphij * are met: 11246586Sdelphij * 1. Redistributions of source code must retain the above copyright 12246586Sdelphij * notice, this list of conditions and the following disclaimer. 13246586Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 14246586Sdelphij * notice, this list of conditions and the following disclaimer in the 15246586Sdelphij * documentation and/or other materials provided with the distribution. 16246586Sdelphij * 17246586Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18246586Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19246586Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20246586Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21246586Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22246586Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23246586Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24246586Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25246586Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26246586Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27246586Sdelphij * SUCH DAMAGE. 28246586Sdelphij */ 29246586Sdelphij 30246586Sdelphij#include <sys/cdefs.h> 31246586Sdelphij__FBSDID("$FreeBSD: head/sys/boot/fdt/fdt_loader_cmd.c 247045 2013-02-20 16:32:38Z kientzle $"); 32246586Sdelphij 33246586Sdelphij#include <stand.h> 34246586Sdelphij#include <fdt.h> 35246586Sdelphij#include <libfdt.h> 36246586Sdelphij#include <sys/param.h> 37246586Sdelphij#include <sys/linker.h> 38246586Sdelphij#include <machine/elf.h> 39246586Sdelphij 40246586Sdelphij#include "bootstrap.h" 41246586Sdelphij#include "glue.h" 42246586Sdelphij 43246586Sdelphij#ifdef DEBUG 44246586Sdelphij#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 45246586Sdelphij printf(fmt,##args); } while (0) 46246586Sdelphij#else 47246586Sdelphij#define debugf(fmt, args...) 48246586Sdelphij#endif 49246586Sdelphij 50246586Sdelphij#define FDT_CWD_LEN 256 51246586Sdelphij#define FDT_MAX_DEPTH 6 52246586Sdelphij 53246586Sdelphij#define FDT_PROP_SEP " = " 54246586Sdelphij 55246586Sdelphij#define STR(number) #number 56246586Sdelphij#define STRINGIFY(number) STR(number) 57246586Sdelphij 58246586Sdelphij#define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l) 59246586Sdelphij#define COPYIN(s,d,l) archsw.arch_copyin(s, d, l) 60246586Sdelphij 61246586Sdelphij#define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb" 62246586Sdelphij 63246586Sdelphij#define CMD_REQUIRES_BLOB 0x01 64246586Sdelphij 65246586Sdelphij/* Local copy of FDT */ 66246586Sdelphijstatic struct fdt_header *fdtp = NULL; 67246586Sdelphij/* Size of FDT blob */ 68246586Sdelphijstatic size_t fdtp_size = 0; 69246586Sdelphij/* Location of FDT in kernel or module */ 70246586Sdelphijstatic vm_offset_t fdtp_va = 0; 71246586Sdelphij 72246586Sdelphijstatic int fdt_load_dtb(vm_offset_t va); 73246586Sdelphij 74246586Sdelphijstatic int fdt_cmd_nyi(int argc, char *argv[]); 75246586Sdelphij 76246586Sdelphijstatic int fdt_cmd_addr(int argc, char *argv[]); 77246586Sdelphijstatic int fdt_cmd_mkprop(int argc, char *argv[]); 78246586Sdelphijstatic int fdt_cmd_cd(int argc, char *argv[]); 79246586Sdelphijstatic int fdt_cmd_hdr(int argc, char *argv[]); 80246586Sdelphijstatic int fdt_cmd_ls(int argc, char *argv[]); 81246586Sdelphijstatic int fdt_cmd_prop(int argc, char *argv[]); 82246586Sdelphijstatic int fdt_cmd_pwd(int argc, char *argv[]); 83246586Sdelphijstatic int fdt_cmd_rm(int argc, char *argv[]); 84246586Sdelphijstatic int fdt_cmd_mknode(int argc, char *argv[]); 85246586Sdelphijstatic int fdt_cmd_mres(int argc, char *argv[]); 86246586Sdelphij 87246586Sdelphijtypedef int cmdf_t(int, char *[]); 88246586Sdelphij 89246586Sdelphijstruct cmdtab { 90246586Sdelphij char *name; 91246586Sdelphij cmdf_t *handler; 92246586Sdelphij int flags; 93246586Sdelphij}; 94246586Sdelphij 95246586Sdelphijstatic const struct cmdtab commands[] = { 96246586Sdelphij { "addr", &fdt_cmd_addr, 0 }, 97246586Sdelphij { "alias", &fdt_cmd_nyi, 0 }, 98246586Sdelphij { "cd", &fdt_cmd_cd, CMD_REQUIRES_BLOB }, 99246586Sdelphij { "header", &fdt_cmd_hdr, CMD_REQUIRES_BLOB }, 100246586Sdelphij { "ls", &fdt_cmd_ls, CMD_REQUIRES_BLOB }, 101246586Sdelphij { "mknode", &fdt_cmd_mknode, CMD_REQUIRES_BLOB }, 102246586Sdelphij { "mkprop", &fdt_cmd_mkprop, CMD_REQUIRES_BLOB }, 103246586Sdelphij { "mres", &fdt_cmd_mres, CMD_REQUIRES_BLOB }, 104246586Sdelphij { "prop", &fdt_cmd_prop, CMD_REQUIRES_BLOB }, 105246586Sdelphij { "pwd", &fdt_cmd_pwd, CMD_REQUIRES_BLOB }, 106246586Sdelphij { "rm", &fdt_cmd_rm, CMD_REQUIRES_BLOB }, 107246586Sdelphij { NULL, NULL } 108246586Sdelphij}; 109246586Sdelphij 110246586Sdelphijstatic char cwd[FDT_CWD_LEN] = "/"; 111246586Sdelphij 112246586Sdelphijstatic vm_offset_t 113246586Sdelphijfdt_find_static_dtb() 114246586Sdelphij{ 115246586Sdelphij Elf_Dyn dyn; 116246586Sdelphij Elf_Sym sym; 117246586Sdelphij vm_offset_t dyntab, esym, strtab, symtab, fdt_start; 118246586Sdelphij uint64_t offs; 119246586Sdelphij struct preloaded_file *kfp; 120246586Sdelphij struct file_metadata *md; 121246586Sdelphij char *strp; 122246586Sdelphij int sym_count; 123246586Sdelphij 124246586Sdelphij symtab = strtab = dyntab = esym = 0; 125246586Sdelphij strp = NULL; 126246586Sdelphij 127246586Sdelphij offs = __elfN(relocation_offset); 128246586Sdelphij 129246586Sdelphij kfp = file_findfile(NULL, NULL); 130246586Sdelphij if (kfp == NULL) 131246586Sdelphij return (0); 132246586Sdelphij 133246586Sdelphij md = file_findmetadata(kfp, MODINFOMD_ESYM); 134246586Sdelphij if (md == NULL) 135246586Sdelphij return (0); 136246586Sdelphij bcopy(md->md_data, &esym, sizeof(esym)); 137246586Sdelphij /* esym is already offset */ 138246586Sdelphij 139246586Sdelphij md = file_findmetadata(kfp, MODINFOMD_DYNAMIC); 140246586Sdelphij if (md == NULL) 141246586Sdelphij return (0); 142246586Sdelphij bcopy(md->md_data, &dyntab, sizeof(dyntab)); 143246586Sdelphij dyntab += offs; 144246586Sdelphij 145246586Sdelphij /* Locate STRTAB and DYNTAB */ 146246586Sdelphij for (;;) { 147246586Sdelphij COPYOUT(dyntab, &dyn, sizeof(dyn)); 148246586Sdelphij if (dyn.d_tag == DT_STRTAB) { 149246586Sdelphij strtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs; 150246586Sdelphij } else if (dyn.d_tag == DT_SYMTAB) { 151246586Sdelphij symtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs; 152246586Sdelphij } else if (dyn.d_tag == DT_NULL) { 153246586Sdelphij break; 154246586Sdelphij } 155246586Sdelphij dyntab += sizeof(dyn); 156246586Sdelphij } 157246586Sdelphij 158246586Sdelphij if (symtab == 0 || strtab == 0) { 159246586Sdelphij /* 160246586Sdelphij * No symtab? No strtab? That should not happen here, 161246586Sdelphij * and should have been verified during __elfN(loadimage). 162246586Sdelphij * This must be some kind of a bug. 163246586Sdelphij */ 164246586Sdelphij return (0); 165246586Sdelphij } 166246586Sdelphij 167246586Sdelphij sym_count = (int)(esym - symtab) / sizeof(Elf_Sym); 168246586Sdelphij 169246586Sdelphij /* 170246586Sdelphij * The most efficent way to find a symbol would be to calculate a 171246586Sdelphij * hash, find proper bucket and chain, and thus find a symbol. 172246586Sdelphij * However, that would involve code duplication (e.g. for hash 173246586Sdelphij * function). So we're using simpler and a bit slower way: we're 174246586Sdelphij * iterating through symbols, searching for the one which name is 175246586Sdelphij * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, 176246586Sdelphij * we are eliminating symbols type of which is not STT_NOTYPE, or(and) 177246586Sdelphij * those which binding attribute is not STB_GLOBAL. 178246586Sdelphij */ 179246586Sdelphij fdt_start = 0; 180246586Sdelphij while (sym_count > 0 && fdt_start == 0) { 181246586Sdelphij COPYOUT(symtab, &sym, sizeof(sym)); 182246586Sdelphij symtab += sizeof(sym); 183246586Sdelphij --sym_count; 184246586Sdelphij if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || 185246586Sdelphij ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) 186246586Sdelphij continue; 187246586Sdelphij strp = strdupout(strtab + sym.st_name); 188246586Sdelphij if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) 189246586Sdelphij fdt_start = (vm_offset_t)sym.st_value + offs; 190246586Sdelphij free(strp); 191246586Sdelphij } 192246586Sdelphij printf("fdt_start: 0x%08jX\n", (intmax_t)fdt_start); 193246586Sdelphij return (fdt_start); 194246586Sdelphij} 195246586Sdelphij 196246586Sdelphijstatic int 197246586Sdelphijfdt_load_dtb(vm_offset_t va) 198246586Sdelphij{ 199246586Sdelphij struct fdt_header header; 200246586Sdelphij int err; 201246586Sdelphij 202246586Sdelphij COPYOUT(va, &header, sizeof(header)); 203246586Sdelphij err = fdt_check_header(&header); 204246586Sdelphij if (err < 0) { 205246586Sdelphij if (err == -FDT_ERR_BADVERSION) 206246586Sdelphij sprintf(command_errbuf, 207246586Sdelphij "incompatible blob version: %d, should be: %d", 208246586Sdelphij fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); 209246586Sdelphij 210246586Sdelphij else 211246586Sdelphij sprintf(command_errbuf, "error validating blob: %s", 212246586Sdelphij fdt_strerror(err)); 213246586Sdelphij return (1); 214246586Sdelphij } 215246586Sdelphij 216246586Sdelphij /* 217246586Sdelphij * Release previous blob 218246586Sdelphij */ 219246586Sdelphij if (fdtp) 220246586Sdelphij free(fdtp); 221246586Sdelphij 222246586Sdelphij fdtp_size = fdt_totalsize(&header); 223246586Sdelphij fdtp = malloc(fdtp_size); 224246586Sdelphij 225246586Sdelphij if (fdtp == NULL) { 226246586Sdelphij command_errmsg = "can't allocate memory for device tree copy"; 227246586Sdelphij return (1); 228246586Sdelphij } 229246586Sdelphij 230246586Sdelphij fdtp_va = va; 231246586Sdelphij COPYOUT(va, fdtp, fdtp_size); 232246586Sdelphij debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size); 233246586Sdelphij 234246586Sdelphij return (0); 235246586Sdelphij} 236246586Sdelphij 237246586Sdelphijstatic int 238246586Sdelphijfdt_load_dtb_addr(struct fdt_header *header) 239246586Sdelphij{ 240246586Sdelphij struct preloaded_file *bfp; 241246586Sdelphij 242246586Sdelphij bfp = mem_load_raw("dtb", "memory.dtb", header, fdt_totalsize(header)); 243246586Sdelphij if (bfp == NULL) { 244246586Sdelphij command_errmsg = "unable to copy DTB into module directory"; 245246586Sdelphij return (1); 246246586Sdelphij } 247246586Sdelphij return fdt_load_dtb(bfp->f_addr); 248246586Sdelphij} 249246586Sdelphij 250246586Sdelphijstatic int 251246586Sdelphijfdt_setup_fdtp() 252246586Sdelphij{ 253246586Sdelphij struct preloaded_file *bfp; 254246586Sdelphij struct fdt_header *hdr; 255246586Sdelphij const char *s, *p; 256246586Sdelphij vm_offset_t va; 257246586Sdelphij 258246586Sdelphij if ((bfp = file_findfile(NULL, "dtb")) != NULL) { 259246586Sdelphij printf("Using DTB from loaded file.\n"); 260246586Sdelphij return fdt_load_dtb(bfp->f_addr); 261246586Sdelphij } 262246586Sdelphij 263246586Sdelphij s = ub_env_get("fdtaddr"); 264246586Sdelphij if (s != NULL && *s != '\0') { 265246586Sdelphij hdr = (struct fdt_header *)strtoul(s, &p, 16); 266246586Sdelphij if (*p == '\0') { 267246586Sdelphij printf("Using DTB provided by U-Boot.\n"); 268246586Sdelphij return fdt_load_dtb_addr(hdr); 269246586Sdelphij } 270246586Sdelphij } 271246586Sdelphij 272246586Sdelphij if ((va = fdt_find_static_dtb()) != 0) { 273246586Sdelphij printf("Using DTB compiled into kernel.\n"); 274246586Sdelphij return (fdt_load_dtb(va)); 275246586Sdelphij } 276246586Sdelphij 277246586Sdelphij command_errmsg = "no device tree blob found!"; 278246586Sdelphij return (1); 279246586Sdelphij} 280246586Sdelphij 281246586Sdelphij#define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 282246586Sdelphij (cellbuf), (lim), (cellsize), 0); 283246586Sdelphij 284246586Sdelphij/* Force using base 16 */ 285246586Sdelphij#define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 286246586Sdelphij (cellbuf), (lim), (cellsize), 16); 287246586Sdelphij 288246586Sdelphijstatic int 289246586Sdelphij_fdt_strtovect(char *str, void *cellbuf, int lim, unsigned char cellsize, 290246586Sdelphij uint8_t base) 291246586Sdelphij{ 292246586Sdelphij char *buf = str; 293246586Sdelphij char *end = str + strlen(str) - 2; 294246586Sdelphij uint32_t *u32buf = NULL; 295246586Sdelphij uint8_t *u8buf = NULL; 296246586Sdelphij int cnt = 0; 297246586Sdelphij 298246586Sdelphij if (cellsize == sizeof(uint32_t)) 299246586Sdelphij u32buf = (uint32_t *)cellbuf; 300246586Sdelphij else 301246586Sdelphij u8buf = (uint8_t *)cellbuf; 302246586Sdelphij 303246586Sdelphij if (lim == 0) 304246586Sdelphij return (0); 305246586Sdelphij 306246586Sdelphij while (buf < end) { 307246586Sdelphij 308246586Sdelphij /* Skip white whitespace(s)/separators */ 309 while (!isxdigit(*buf) && buf < end) 310 buf++; 311 312 if (u32buf != NULL) 313 u32buf[cnt] = 314 cpu_to_fdt32((uint32_t)strtol(buf, NULL, base)); 315 316 else 317 u8buf[cnt] = (uint8_t)strtol(buf, NULL, base); 318 319 if (cnt + 1 <= lim - 1) 320 cnt++; 321 else 322 break; 323 buf++; 324 /* Find another number */ 325 while ((isxdigit(*buf) || *buf == 'x') && buf < end) 326 buf++; 327 } 328 return (cnt); 329} 330 331#define TMP_MAX_ETH 8 332 333void 334fixup_ethernet(const char *env, char *ethstr, int *eth_no, int len) 335{ 336 char *end, *str; 337 uint8_t tmp_addr[6]; 338 int i, n; 339 340 /* Extract interface number */ 341 i = strtol(env + 3, &end, 10); 342 if (end == (env + 3)) 343 /* 'ethaddr' means interface 0 address */ 344 n = 0; 345 else 346 n = i; 347 348 if (n > TMP_MAX_ETH) 349 return; 350 351 str = ub_env_get(env); 352 353 /* Convert macaddr string into a vector of uints */ 354 fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); 355 if (n != 0) { 356 i = strlen(env) - 7; 357 strncpy(ethstr + 8, env + 3, i); 358 } 359 /* Set actual property to a value from vect */ 360 fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), 361 "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); 362 363 /* Clear ethernet..XXXX.. string */ 364 bzero(ethstr + 8, len - 8); 365 366 if (n + 1 > *eth_no) 367 *eth_no = n + 1; 368} 369 370void 371fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq) 372{ 373 int lo, o = 0, o2, maxo = 0, depth; 374 const uint32_t zero = 0; 375 376 /* We want to modify every subnode of /cpus */ 377 o = fdt_path_offset(fdtp, "/cpus"); 378 if (o < 0) 379 return; 380 381 /* maxo should contain offset of node next to /cpus */ 382 depth = 0; 383 maxo = o; 384 while (depth != -1) 385 maxo = fdt_next_node(fdtp, maxo, &depth); 386 387 /* Find CPU frequency properties */ 388 o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency", 389 &zero, sizeof(uint32_t)); 390 391 o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero, 392 sizeof(uint32_t)); 393 394 lo = MIN(o, o2); 395 396 while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) { 397 398 o = fdt_node_offset_by_prop_value(fdtp, lo, 399 "clock-frequency", &zero, sizeof(uint32_t)); 400 401 o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency", 402 &zero, sizeof(uint32_t)); 403 404 /* We're only interested in /cpus subnode(s) */ 405 if (lo > maxo) 406 break; 407 408 fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency", 409 (uint32_t)cpufreq); 410 411 fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency", 412 (uint32_t)busfreq); 413 414 lo = MIN(o, o2); 415 } 416} 417 418int 419fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) 420{ 421 int cells_in_tuple, i, tuples, tuple_size; 422 uint32_t cur_start, cur_size; 423 424 cells_in_tuple = (addr_cells + size_cells); 425 tuple_size = cells_in_tuple * sizeof(uint32_t); 426 tuples = len / tuple_size; 427 if (tuples == 0) 428 return (EINVAL); 429 430 for (i = 0; i < tuples; i++) { 431 if (addr_cells == 2) 432 cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); 433 else 434 cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); 435 436 if (size_cells == 2) 437 cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); 438 else 439 cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); 440 441 if (cur_size == 0) 442 return (EINVAL); 443 444 debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", 445 i, cur_start, cur_size); 446 } 447 return (0); 448} 449 450void 451fixup_memory(struct sys_info *si) 452{ 453 struct mem_region *curmr; 454 uint32_t addr_cells, size_cells; 455 uint32_t *addr_cellsp, *reg, *size_cellsp; 456 int err, i, len, memory, realmrno, root; 457 uint8_t *buf, *sb; 458 uint64_t rstart, rsize; 459 int reserved; 460 461 root = fdt_path_offset(fdtp, "/"); 462 if (root < 0) { 463 sprintf(command_errbuf, "Could not find root node !"); 464 return; 465 } 466 467 memory = fdt_path_offset(fdtp, "/memory"); 468 if (memory <= 0) { 469 /* Create proper '/memory' node. */ 470 memory = fdt_add_subnode(fdtp, root, "memory"); 471 if (memory <= 0) { 472 sprintf(command_errbuf, "Could not fixup '/memory' " 473 "node, error code : %d!\n", memory); 474 return; 475 } 476 477 err = fdt_setprop(fdtp, memory, "device_type", "memory", 478 sizeof("memory")); 479 480 if (err < 0) 481 return; 482 } 483 484 addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", 485 NULL); 486 size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); 487 488 if (addr_cellsp == NULL || size_cellsp == NULL) { 489 sprintf(command_errbuf, "Could not fixup '/memory' node : " 490 "%s %s property not found in root node!\n", 491 (!addr_cellsp) ? "#address-cells" : "", 492 (!size_cellsp) ? "#size-cells" : ""); 493 return; 494 } 495 496 addr_cells = fdt32_to_cpu(*addr_cellsp); 497 size_cells = fdt32_to_cpu(*size_cellsp); 498 499 /* 500 * Convert memreserve data to memreserve property 501 * Check if property already exists 502 */ 503 reserved = fdt_num_mem_rsv(fdtp); 504 if (reserved && 505 (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) { 506 len = (addr_cells + size_cells) * reserved * sizeof(uint32_t); 507 sb = buf = (uint8_t *)malloc(len); 508 if (!buf) 509 return; 510 511 bzero(buf, len); 512 513 for (i = 0; i < reserved; i++) { 514 curmr = &si->mr[i]; 515 if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize)) 516 break; 517 if (rsize) { 518 /* Ensure endianess, and put cells into a buffer */ 519 if (addr_cells == 2) 520 *(uint64_t *)buf = 521 cpu_to_fdt64(rstart); 522 else 523 *(uint32_t *)buf = 524 cpu_to_fdt32(rstart); 525 526 buf += sizeof(uint32_t) * addr_cells; 527 if (size_cells == 2) 528 *(uint64_t *)buf = 529 cpu_to_fdt64(rsize); 530 else 531 *(uint32_t *)buf = 532 cpu_to_fdt32(rsize); 533 534 buf += sizeof(uint32_t) * size_cells; 535 } 536 } 537 538 /* Set property */ 539 if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0) 540 printf("Could not fixup 'memreserve' property.\n"); 541 542 free(sb); 543 } 544 545 /* Count valid memory regions entries in sysinfo. */ 546 realmrno = si->mr_no; 547 for (i = 0; i < si->mr_no; i++) 548 if (si->mr[i].start == 0 && si->mr[i].size == 0) 549 realmrno--; 550 551 if (realmrno == 0) { 552 sprintf(command_errbuf, "Could not fixup '/memory' node : " 553 "sysinfo doesn't contain valid memory regions info!\n"); 554 return; 555 } 556 557 if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg", 558 &len)) != NULL) { 559 560 if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0) 561 /* 562 * Do not apply fixup if existing 'reg' property 563 * seems to be valid. 564 */ 565 return; 566 } 567 568 len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); 569 sb = buf = (uint8_t *)malloc(len); 570 if (!buf) 571 return; 572 573 bzero(buf, len); 574 575 for (i = 0; i < si->mr_no; i++) { 576 curmr = &si->mr[i]; 577 if (curmr->size != 0) { 578 /* Ensure endianess, and put cells into a buffer */ 579 if (addr_cells == 2) 580 *(uint64_t *)buf = 581 cpu_to_fdt64(curmr->start); 582 else 583 *(uint32_t *)buf = 584 cpu_to_fdt32(curmr->start); 585 586 buf += sizeof(uint32_t) * addr_cells; 587 if (size_cells == 2) 588 *(uint64_t *)buf = 589 cpu_to_fdt64(curmr->size); 590 else 591 *(uint32_t *)buf = 592 cpu_to_fdt32(curmr->size); 593 594 buf += sizeof(uint32_t) * size_cells; 595 } 596 } 597 598 /* Set property */ 599 if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) 600 sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); 601 602 free(sb); 603} 604 605void 606fixup_stdout(const char *env) 607{ 608 const char *str; 609 char *ptr; 610 int serialno; 611 int len, no, sero; 612 const struct fdt_property *prop; 613 char *tmp[10]; 614 615 str = ub_env_get(env); 616 ptr = (char *)str + strlen(str) - 1; 617 while (ptr > str && isdigit(*(str - 1))) 618 str--; 619 620 if (ptr == str) 621 return; 622 623 serialno = (int)strtol(ptr, NULL, 0); 624 no = fdt_path_offset(fdtp, "/chosen"); 625 if (no < 0) 626 return; 627 628 prop = fdt_get_property(fdtp, no, "stdout", &len); 629 630 /* If /chosen/stdout does not extist, create it */ 631 if (prop == NULL || (prop != NULL && len == 0)) { 632 633 bzero(tmp, 10 * sizeof(char)); 634 strcpy((char *)&tmp, "serial"); 635 if (strlen(ptr) > 3) 636 /* Serial number too long */ 637 return; 638 639 strncpy((char *)tmp + 6, ptr, 3); 640 sero = fdt_path_offset(fdtp, (const char *)tmp); 641 if (sero < 0) 642 /* 643 * If serial device we're trying to assign 644 * stdout to doesn't exist in DT -- return. 645 */ 646 return; 647 648 fdt_setprop(fdtp, no, "stdout", &tmp, 649 strlen((char *)&tmp) + 1); 650 fdt_setprop(fdtp, no, "stdin", &tmp, 651 strlen((char *)&tmp) + 1); 652 } 653} 654 655/* 656 * Locate the blob, fix it up and return its location. 657 */ 658static vm_offset_t 659fdt_fixup(void) 660{ 661 const char *env; 662 char *ethstr; 663 int chosen, err, eth_no, len; 664 struct sys_info *si; 665 666 env = NULL; 667 eth_no = 0; 668 ethstr = NULL; 669 len = 0; 670 671 if (fdtp == NULL) { 672 err = fdt_setup_fdtp(); 673 if (err) { 674 sprintf(command_errbuf, "No valid device tree blob found!"); 675 return (0); 676 } 677 } 678 679 /* Create /chosen node (if not exists) */ 680 if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == 681 -FDT_ERR_NOTFOUND) 682 chosen = fdt_add_subnode(fdtp, 0, "chosen"); 683 684 /* Value assigned to fixup-applied does not matter. */ 685 if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) 686 goto success; 687 688 /* Acquire sys_info */ 689 si = ub_get_sys_info(); 690 691 while ((env = ub_env_enum(env)) != NULL) { 692 if (strncmp(env, "eth", 3) == 0 && 693 strncmp(env + (strlen(env) - 4), "addr", 4) == 0) { 694 /* 695 * Handle Ethernet addrs: parse uboot env eth%daddr 696 */ 697 698 if (!eth_no) { 699 /* 700 * Check how many chars we will need to store 701 * maximal eth iface number. 702 */ 703 len = strlen(STRINGIFY(TMP_MAX_ETH)) + 704 strlen("ethernet"); 705 706 /* 707 * Reserve mem for string "ethernet" and len 708 * chars for iface no. 709 */ 710 ethstr = (char *)malloc(len * sizeof(char)); 711 bzero(ethstr, len * sizeof(char)); 712 strcpy(ethstr, "ethernet0"); 713 } 714 715 /* Modify blob */ 716 fixup_ethernet(env, ethstr, ð_no, len); 717 718 } else if (strcmp(env, "consoledev") == 0) 719 fixup_stdout(env); 720 } 721 722 /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */ 723 fixup_cpubusfreqs(si->clk_cpu, si->clk_bus); 724 725 /* Fixup memory regions */ 726 fixup_memory(si); 727 728 fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); 729 730success: 731 /* Overwrite the FDT with the fixed version. */ 732 COPYIN(fdtp, fdtp_va, fdtp_size); 733 return (fdtp_va); 734} 735 736/* 737 * Copy DTB blob to specified location and its return size 738 */ 739int 740fdt_copy(vm_offset_t va) 741{ 742 int err; 743 744 if (fdtp == NULL) { 745 err = fdt_setup_fdtp(); 746 if (err) { 747 printf("No valid device tree blob found!"); 748 return (0); 749 } 750 } 751 752 if (fdt_fixup() == 0) 753 return (0); 754 755 COPYIN(fdtp, va, fdtp_size); 756 return (fdtp_size); 757} 758 759 760 761int 762command_fdt_internal(int argc, char *argv[]) 763{ 764 cmdf_t *cmdh; 765 int flags; 766 char *cmd; 767 int i, err; 768 769 if (argc < 2) { 770 command_errmsg = "usage is 'fdt <command> [<args>]"; 771 return (CMD_ERROR); 772 } 773 774 /* 775 * Validate fdt <command>. 776 */ 777 cmd = strdup(argv[1]); 778 i = 0; 779 cmdh = NULL; 780 while (!(commands[i].name == NULL)) { 781 if (strcmp(cmd, commands[i].name) == 0) { 782 /* found it */ 783 cmdh = commands[i].handler; 784 flags = commands[i].flags; 785 break; 786 } 787 i++; 788 } 789 if (cmdh == NULL) { 790 command_errmsg = "unknown command"; 791 return (CMD_ERROR); 792 } 793 794 if (flags & CMD_REQUIRES_BLOB) { 795 /* 796 * Check if uboot env vars were parsed already. If not, do it now. 797 */ 798 if (fdt_fixup() == 0) 799 return (CMD_ERROR); 800 } 801 802 /* 803 * Call command handler. 804 */ 805 err = (*cmdh)(argc, argv); 806 807 return (err); 808} 809 810static int 811fdt_cmd_addr(int argc, char *argv[]) 812{ 813 struct fdt_header *hdr; 814 const char *addr, *cp; 815 816 if (argc > 2) 817 addr = argv[2]; 818 else { 819 sprintf(command_errbuf, "no address specified"); 820 return (CMD_ERROR); 821 } 822 823 hdr = (struct fdt_header *)strtoul(addr, &cp, 0); 824 if (cp == addr) { 825 sprintf(command_errbuf, "Invalid address: %s", addr); 826 return (CMD_ERROR); 827 } 828 829 if (fdt_load_dtb_addr(hdr) != 0) 830 return (CMD_ERROR); 831 832 return (CMD_OK); 833} 834 835static int 836fdt_cmd_cd(int argc, char *argv[]) 837{ 838 char *path; 839 char tmp[FDT_CWD_LEN]; 840 int len, o; 841 842 path = (argc > 2) ? argv[2] : "/"; 843 844 if (path[0] == '/') { 845 len = strlen(path); 846 if (len >= FDT_CWD_LEN) 847 goto fail; 848 } else { 849 /* Handle path specification relative to cwd */ 850 len = strlen(cwd) + strlen(path) + 1; 851 if (len >= FDT_CWD_LEN) 852 goto fail; 853 854 strcpy(tmp, cwd); 855 strcat(tmp, "/"); 856 strcat(tmp, path); 857 path = tmp; 858 } 859 860 o = fdt_path_offset(fdtp, path); 861 if (o < 0) { 862 sprintf(command_errbuf, "could not find node: '%s'", path); 863 return (CMD_ERROR); 864 } 865 866 strcpy(cwd, path); 867 return (CMD_OK); 868 869fail: 870 sprintf(command_errbuf, "path too long: %d, max allowed: %d", 871 len, FDT_CWD_LEN - 1); 872 return (CMD_ERROR); 873} 874 875static int 876fdt_cmd_hdr(int argc __unused, char *argv[] __unused) 877{ 878 char line[80]; 879 int ver; 880 881 if (fdtp == NULL) { 882 command_errmsg = "no device tree blob pointer?!"; 883 return (CMD_ERROR); 884 } 885 886 ver = fdt_version(fdtp); 887 pager_open(); 888 sprintf(line, "\nFlattened device tree header (%p):\n", fdtp); 889 pager_output(line); 890 sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); 891 pager_output(line); 892 sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); 893 pager_output(line); 894 sprintf(line, " off_dt_struct = 0x%08x\n", 895 fdt_off_dt_struct(fdtp)); 896 pager_output(line); 897 sprintf(line, " off_dt_strings = 0x%08x\n", 898 fdt_off_dt_strings(fdtp)); 899 pager_output(line); 900 sprintf(line, " off_mem_rsvmap = 0x%08x\n", 901 fdt_off_mem_rsvmap(fdtp)); 902 pager_output(line); 903 sprintf(line, " version = %d\n", ver); 904 pager_output(line); 905 sprintf(line, " last compatible version = %d\n", 906 fdt_last_comp_version(fdtp)); 907 pager_output(line); 908 if (ver >= 2) { 909 sprintf(line, " boot_cpuid = %d\n", 910 fdt_boot_cpuid_phys(fdtp)); 911 pager_output(line); 912 } 913 if (ver >= 3) { 914 sprintf(line, " size_dt_strings = %d\n", 915 fdt_size_dt_strings(fdtp)); 916 pager_output(line); 917 } 918 if (ver >= 17) { 919 sprintf(line, " size_dt_struct = %d\n", 920 fdt_size_dt_struct(fdtp)); 921 pager_output(line); 922 } 923 pager_close(); 924 925 return (CMD_OK); 926} 927 928static int 929fdt_cmd_ls(int argc, char *argv[]) 930{ 931 const char *prevname[FDT_MAX_DEPTH] = { NULL }; 932 const char *name; 933 char *path; 934 int i, o, depth, len; 935 936 path = (argc > 2) ? argv[2] : NULL; 937 if (path == NULL) 938 path = cwd; 939 940 o = fdt_path_offset(fdtp, path); 941 if (o < 0) { 942 sprintf(command_errbuf, "could not find node: '%s'", path); 943 return (CMD_ERROR); 944 } 945 946 for (depth = 0; 947 (o >= 0) && (depth >= 0); 948 o = fdt_next_node(fdtp, o, &depth)) { 949 950 name = fdt_get_name(fdtp, o, &len); 951 952 if (depth > FDT_MAX_DEPTH) { 953 printf("max depth exceeded: %d\n", depth); 954 continue; 955 } 956 957 prevname[depth] = name; 958 959 /* Skip root (i = 1) when printing devices */ 960 for (i = 1; i <= depth; i++) { 961 if (prevname[i] == NULL) 962 break; 963 964 if (strcmp(cwd, "/") == 0) 965 printf("/"); 966 printf("%s", prevname[i]); 967 } 968 printf("\n"); 969 } 970 971 return (CMD_OK); 972} 973 974static __inline int 975isprint(int c) 976{ 977 978 return (c >= ' ' && c <= 0x7e); 979} 980 981static int 982fdt_isprint(const void *data, int len, int *count) 983{ 984 const char *d; 985 char ch; 986 int yesno, i; 987 988 if (len == 0) 989 return (0); 990 991 d = (const char *)data; 992 if (d[len - 1] != '\0') 993 return (0); 994 995 *count = 0; 996 yesno = 1; 997 for (i = 0; i < len; i++) { 998 ch = *(d + i); 999 if (isprint(ch) || (ch == '\0' && i > 0)) { 1000 /* Count strings */ 1001 if (ch == '\0') 1002 (*count)++; 1003 continue; 1004 } 1005 1006 yesno = 0; 1007 break; 1008 } 1009 1010 return (yesno); 1011} 1012 1013static int 1014fdt_data_str(const void *data, int len, int count, char **buf) 1015{ 1016 char *b, *tmp; 1017 const char *d; 1018 int buf_len, i, l; 1019 1020 /* 1021 * Calculate the length for the string and allocate memory. 1022 * 1023 * Note that 'len' already includes at least one terminator. 1024 */ 1025 buf_len = len; 1026 if (count > 1) { 1027 /* 1028 * Each token had already a terminator buried in 'len', but we 1029 * only need one eventually, don't count space for these. 1030 */ 1031 buf_len -= count - 1; 1032 1033 /* Each consecutive token requires a ", " separator. */ 1034 buf_len += count * 2; 1035 } 1036 1037 /* Add some space for surrounding double quotes. */ 1038 buf_len += count * 2; 1039 1040 /* Note that string being put in 'tmp' may be as big as 'buf_len'. */ 1041 b = (char *)malloc(buf_len); 1042 tmp = (char *)malloc(buf_len); 1043 if (b == NULL) 1044 goto error; 1045 1046 if (tmp == NULL) { 1047 free(b); 1048 goto error; 1049 } 1050 1051 b[0] = '\0'; 1052 1053 /* 1054 * Now that we have space, format the string. 1055 */ 1056 i = 0; 1057 do { 1058 d = (const char *)data + i; 1059 l = strlen(d) + 1; 1060 1061 sprintf(tmp, "\"%s\"%s", d, 1062 (i + l) < len ? ", " : ""); 1063 strcat(b, tmp); 1064 1065 i += l; 1066 1067 } while (i < len); 1068 *buf = b; 1069 1070 free(tmp); 1071 1072 return (0); 1073error: 1074 return (1); 1075} 1076 1077static int 1078fdt_data_cell(const void *data, int len, char **buf) 1079{ 1080 char *b, *tmp; 1081 const uint32_t *c; 1082 int count, i, l; 1083 1084 /* Number of cells */ 1085 count = len / 4; 1086 1087 /* 1088 * Calculate the length for the string and allocate memory. 1089 */ 1090 1091 /* Each byte translates to 2 output characters */ 1092 l = len * 2; 1093 if (count > 1) { 1094 /* Each consecutive cell requires a " " separator. */ 1095 l += (count - 1) * 1; 1096 } 1097 /* Each cell will have a "0x" prefix */ 1098 l += count * 2; 1099 /* Space for surrounding <> and terminator */ 1100 l += 3; 1101 1102 b = (char *)malloc(l); 1103 tmp = (char *)malloc(l); 1104 if (b == NULL) 1105 goto error; 1106 1107 if (tmp == NULL) { 1108 free(b); 1109 goto error; 1110 } 1111 1112 b[0] = '\0'; 1113 strcat(b, "<"); 1114 1115 for (i = 0; i < len; i += 4) { 1116 c = (const uint32_t *)((const uint8_t *)data + i); 1117 sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c), 1118 i < (len - 4) ? " " : ""); 1119 strcat(b, tmp); 1120 } 1121 strcat(b, ">"); 1122 *buf = b; 1123 1124 free(tmp); 1125 1126 return (0); 1127error: 1128 return (1); 1129} 1130 1131static int 1132fdt_data_bytes(const void *data, int len, char **buf) 1133{ 1134 char *b, *tmp; 1135 const char *d; 1136 int i, l; 1137 1138 /* 1139 * Calculate the length for the string and allocate memory. 1140 */ 1141 1142 /* Each byte translates to 2 output characters */ 1143 l = len * 2; 1144 if (len > 1) 1145 /* Each consecutive byte requires a " " separator. */ 1146 l += (len - 1) * 1; 1147 /* Each byte will have a "0x" prefix */ 1148 l += len * 2; 1149 /* Space for surrounding [] and terminator. */ 1150 l += 3; 1151 1152 b = (char *)malloc(l); 1153 tmp = (char *)malloc(l); 1154 if (b == NULL) 1155 goto error; 1156 1157 if (tmp == NULL) { 1158 free(b); 1159 goto error; 1160 } 1161 1162 b[0] = '\0'; 1163 strcat(b, "["); 1164 1165 for (i = 0, d = data; i < len; i++) { 1166 sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : ""); 1167 strcat(b, tmp); 1168 } 1169 strcat(b, "]"); 1170 *buf = b; 1171 1172 free(tmp); 1173 1174 return (0); 1175error: 1176 return (1); 1177} 1178 1179static int 1180fdt_data_fmt(const void *data, int len, char **buf) 1181{ 1182 int count; 1183 1184 if (len == 0) { 1185 *buf = NULL; 1186 return (1); 1187 } 1188 1189 if (fdt_isprint(data, len, &count)) 1190 return (fdt_data_str(data, len, count, buf)); 1191 1192 else if ((len % 4) == 0) 1193 return (fdt_data_cell(data, len, buf)); 1194 1195 else 1196 return (fdt_data_bytes(data, len, buf)); 1197} 1198 1199static int 1200fdt_prop(int offset) 1201{ 1202 char *line, *buf; 1203 const struct fdt_property *prop; 1204 const char *name; 1205 const void *data; 1206 int len, rv; 1207 1208 line = NULL; 1209 prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop)); 1210 if (prop == NULL) 1211 return (1); 1212 1213 name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); 1214 len = fdt32_to_cpu(prop->len); 1215 1216 rv = 0; 1217 buf = NULL; 1218 if (len == 0) { 1219 /* Property without value */ 1220 line = (char *)malloc(strlen(name) + 2); 1221 if (line == NULL) { 1222 rv = 2; 1223 goto out2; 1224 } 1225 sprintf(line, "%s\n", name); 1226 goto out1; 1227 } 1228 1229 /* 1230 * Process property with value 1231 */ 1232 data = prop->data; 1233 1234 if (fdt_data_fmt(data, len, &buf) != 0) { 1235 rv = 3; 1236 goto out2; 1237 } 1238 1239 line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) + 1240 strlen(buf) + 2); 1241 if (line == NULL) { 1242 sprintf(command_errbuf, "could not allocate space for string"); 1243 rv = 4; 1244 goto out2; 1245 } 1246 1247 sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf); 1248 1249out1: 1250 pager_open(); 1251 pager_output(line); 1252 pager_close(); 1253 1254out2: 1255 if (buf) 1256 free(buf); 1257 1258 if (line) 1259 free(line); 1260 1261 return (rv); 1262} 1263 1264static int 1265fdt_modprop(int nodeoff, char *propname, void *value, char mode) 1266{ 1267 uint32_t cells[100]; 1268 char *buf; 1269 int len, rv; 1270 const struct fdt_property *p; 1271 1272 p = fdt_get_property(fdtp, nodeoff, propname, NULL); 1273 1274 if (p != NULL) { 1275 if (mode == 1) { 1276 /* Adding inexistant value in mode 1 is forbidden */ 1277 sprintf(command_errbuf, "property already exists!"); 1278 return (CMD_ERROR); 1279 } 1280 } else if (mode == 0) { 1281 sprintf(command_errbuf, "property does not exist!"); 1282 return (CMD_ERROR); 1283 } 1284 len = strlen(value); 1285 rv = 0; 1286 buf = (char *)value; 1287 1288 switch (*buf) { 1289 case '&': 1290 /* phandles */ 1291 break; 1292 case '<': 1293 /* Data cells */ 1294 len = fdt_strtovect(buf, (void *)&cells, 100, 1295 sizeof(uint32_t)); 1296 1297 rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1298 len * sizeof(uint32_t)); 1299 break; 1300 case '[': 1301 /* Data bytes */ 1302 len = fdt_strtovect(buf, (void *)&cells, 100, 1303 sizeof(uint8_t)); 1304 1305 rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1306 len * sizeof(uint8_t)); 1307 break; 1308 case '"': 1309 default: 1310 /* Default -- string */ 1311 rv = fdt_setprop_string(fdtp, nodeoff, propname, value); 1312 break; 1313 } 1314 1315 if (rv != 0) { 1316 if (rv == -FDT_ERR_NOSPACE) 1317 sprintf(command_errbuf, 1318 "Device tree blob is too small!\n"); 1319 else 1320 sprintf(command_errbuf, 1321 "Could not add/modify property!\n"); 1322 } else { 1323 COPYIN(fdtp, fdtp_va, fdtp_size); 1324 } 1325 return (rv); 1326} 1327 1328/* Merge strings from argv into a single string */ 1329static int 1330fdt_merge_strings(int argc, char *argv[], int start, char **buffer) 1331{ 1332 char *buf; 1333 int i, idx, sz; 1334 1335 *buffer = NULL; 1336 sz = 0; 1337 1338 for (i = start; i < argc; i++) 1339 sz += strlen(argv[i]); 1340 1341 /* Additional bytes for whitespaces between args */ 1342 sz += argc - start; 1343 1344 buf = (char *)malloc(sizeof(char) * sz); 1345 bzero(buf, sizeof(char) * sz); 1346 1347 if (buf == NULL) { 1348 sprintf(command_errbuf, "could not allocate space " 1349 "for string"); 1350 return (1); 1351 } 1352 1353 idx = 0; 1354 for (i = start, idx = 0; i < argc; i++) { 1355 strcpy(buf + idx, argv[i]); 1356 idx += strlen(argv[i]); 1357 buf[idx] = ' '; 1358 idx++; 1359 } 1360 buf[sz - 1] = '\0'; 1361 *buffer = buf; 1362 return (0); 1363} 1364 1365/* Extract offset and name of node/property from a given path */ 1366static int 1367fdt_extract_nameloc(char **pathp, char **namep, int *nodeoff) 1368{ 1369 int o; 1370 char *path = *pathp, *name = NULL, *subpath = NULL; 1371 1372 subpath = strrchr(path, '/'); 1373 if (subpath == NULL) { 1374 o = fdt_path_offset(fdtp, cwd); 1375 name = path; 1376 path = (char *)&cwd; 1377 } else { 1378 *subpath = '\0'; 1379 if (strlen(path) == 0) 1380 path = cwd; 1381 1382 name = subpath + 1; 1383 o = fdt_path_offset(fdtp, path); 1384 } 1385 1386 if (strlen(name) == 0) { 1387 sprintf(command_errbuf, "name not specified"); 1388 return (1); 1389 } 1390 if (o < 0) { 1391 sprintf(command_errbuf, "could not find node: '%s'", path); 1392 return (1); 1393 } 1394 *namep = name; 1395 *nodeoff = o; 1396 *pathp = path; 1397 return (0); 1398} 1399 1400static int 1401fdt_cmd_prop(int argc, char *argv[]) 1402{ 1403 char *path, *propname, *value; 1404 int o, next, depth, rv; 1405 uint32_t tag; 1406 1407 path = (argc > 2) ? argv[2] : NULL; 1408 1409 value = NULL; 1410 1411 if (argc > 3) { 1412 /* Merge property value strings into one */ 1413 if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1414 return (CMD_ERROR); 1415 } else 1416 value = NULL; 1417 1418 if (path == NULL) 1419 path = cwd; 1420 1421 rv = CMD_OK; 1422 1423 if (value) { 1424 /* If value is specified -- try to modify prop. */ 1425 if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1426 return (CMD_ERROR); 1427 1428 rv = fdt_modprop(o, propname, value, 0); 1429 if (rv) 1430 return (CMD_ERROR); 1431 return (CMD_OK); 1432 1433 } 1434 /* User wants to display properties */ 1435 o = fdt_path_offset(fdtp, path); 1436 1437 if (o < 0) { 1438 sprintf(command_errbuf, "could not find node: '%s'", path); 1439 rv = CMD_ERROR; 1440 goto out; 1441 } 1442 1443 depth = 0; 1444 while (depth >= 0) { 1445 tag = fdt_next_tag(fdtp, o, &next); 1446 switch (tag) { 1447 case FDT_NOP: 1448 break; 1449 case FDT_PROP: 1450 if (depth > 1) 1451 /* Don't process properties of nested nodes */ 1452 break; 1453 1454 if (fdt_prop(o) != 0) { 1455 sprintf(command_errbuf, "could not process " 1456 "property"); 1457 rv = CMD_ERROR; 1458 goto out; 1459 } 1460 break; 1461 case FDT_BEGIN_NODE: 1462 depth++; 1463 if (depth > FDT_MAX_DEPTH) { 1464 printf("warning: nesting too deep: %d\n", 1465 depth); 1466 goto out; 1467 } 1468 break; 1469 case FDT_END_NODE: 1470 depth--; 1471 if (depth == 0) 1472 /* 1473 * This is the end of our starting node, force 1474 * the loop finish. 1475 */ 1476 depth--; 1477 break; 1478 } 1479 o = next; 1480 } 1481out: 1482 return (rv); 1483} 1484 1485static int 1486fdt_cmd_mkprop(int argc, char *argv[]) 1487{ 1488 int o; 1489 char *path, *propname, *value; 1490 1491 path = (argc > 2) ? argv[2] : NULL; 1492 1493 value = NULL; 1494 1495 if (argc > 3) { 1496 /* Merge property value strings into one */ 1497 if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1498 return (CMD_ERROR); 1499 } else 1500 value = NULL; 1501 1502 if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1503 return (CMD_ERROR); 1504 1505 if (fdt_modprop(o, propname, value, 1)) 1506 return (CMD_ERROR); 1507 1508 COPYIN(fdtp, fdtp_va, fdtp_size); 1509 return (CMD_OK); 1510} 1511 1512static int 1513fdt_cmd_rm(int argc, char *argv[]) 1514{ 1515 int o, rv; 1516 char *path = NULL, *propname; 1517 1518 if (argc > 2) 1519 path = argv[2]; 1520 else { 1521 sprintf(command_errbuf, "no node/property name specified"); 1522 return (CMD_ERROR); 1523 } 1524 1525 o = fdt_path_offset(fdtp, path); 1526 if (o < 0) { 1527 /* If node not found -- try to find & delete property */ 1528 if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1529 return (CMD_ERROR); 1530 1531 if ((rv = fdt_delprop(fdtp, o, propname)) != 0) { 1532 sprintf(command_errbuf, "could not delete" 1533 "%s\n", (rv == -FDT_ERR_NOTFOUND) ? 1534 "(property/node does not exist)" : ""); 1535 return (CMD_ERROR); 1536 1537 } else 1538 return (CMD_OK); 1539 } 1540 /* If node exists -- remove node */ 1541 rv = fdt_del_node(fdtp, o); 1542 if (rv) { 1543 sprintf(command_errbuf, "could not delete node"); 1544 return (CMD_ERROR); 1545 } else { 1546 COPYIN(fdtp, fdtp_va, fdtp_size); 1547 } 1548 return (CMD_OK); 1549} 1550 1551static int 1552fdt_cmd_mknode(int argc, char *argv[]) 1553{ 1554 int o, rv; 1555 char *path = NULL, *nodename = NULL; 1556 1557 if (argc > 2) 1558 path = argv[2]; 1559 else { 1560 sprintf(command_errbuf, "no node name specified"); 1561 return (CMD_ERROR); 1562 } 1563 1564 if (fdt_extract_nameloc(&path, &nodename, &o) != 0) 1565 return (CMD_ERROR); 1566 1567 rv = fdt_add_subnode(fdtp, o, nodename); 1568 1569 if (rv < 0) { 1570 if (rv == -FDT_ERR_NOSPACE) 1571 sprintf(command_errbuf, 1572 "Device tree blob is too small!\n"); 1573 else 1574 sprintf(command_errbuf, 1575 "Could not add node!\n"); 1576 return (CMD_ERROR); 1577 } else { 1578 COPYIN(fdtp, fdtp_va, fdtp_size); 1579 } 1580 return (CMD_OK); 1581} 1582 1583static int 1584fdt_cmd_pwd(int argc, char *argv[]) 1585{ 1586 char line[FDT_CWD_LEN]; 1587 1588 pager_open(); 1589 sprintf(line, "%s\n", cwd); 1590 pager_output(line); 1591 pager_close(); 1592 return (CMD_OK); 1593} 1594 1595static int 1596fdt_cmd_mres(int argc, char *argv[]) 1597{ 1598 uint64_t start, size; 1599 int i, total; 1600 char line[80]; 1601 1602 pager_open(); 1603 total = fdt_num_mem_rsv(fdtp); 1604 if (total > 0) { 1605 pager_output("Reserved memory regions:\n"); 1606 for (i = 0; i < total; i++) { 1607 fdt_get_mem_rsv(fdtp, i, &start, &size); 1608 sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", 1609 i, start, size); 1610 pager_output(line); 1611 } 1612 } else 1613 pager_output("No reserved memory regions\n"); 1614 pager_close(); 1615 1616 return (CMD_OK); 1617} 1618 1619static int 1620fdt_cmd_nyi(int argc, char *argv[]) 1621{ 1622 1623 printf("command not yet implemented\n"); 1624 return (CMD_ERROR); 1625} 1626