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

Cache object: ab1b439036e94126f0ae44cf91f0c82a


[ 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.