The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/boot/fdt/fdt_loader_cmd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 047c30a4165037e75ae04b66ff725cf5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.