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

Cache object: 7becb7bef07148c9da437eb6cc666972


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