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

Cache object: f925a75dd6b364e08b273e8e94afd6f5


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